You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose仅子Schema的post('save')中间件触发,父Schema无响应

Mongoose父Schema的post('save')中间件不执行,仅子Schema中间件生效

问题现象

为Mongoose的父子Schema分别添加post('save')中间件后,保存父文档时,仅子Schema的中间件会输出日志,父Schema的中间件无任何响应。

相关代码

ContentModel.js

import mongoose from 'mongoose'
import { nanoid } from 'nanoid'

const ContentChildSchema        = mongoose.Schema({
  blockId: { type: String, default: () => `block-${ nanoid(7) }` },
  element: { type: String, default: 'div' },
  content: { type: String },
  contentEditable: { type: Boolean, default: false },
  order: { type: Number },
  children: [],
})

const ContentParentSchema       = mongoose.Schema({
  blockContainerId: { type: String, default: () => `block-container-${ nanoid(7) }` },
  page: { type: String, required: true },
  element: { type: String, default: 'div' },
  contentEditable: { type: Boolean },
  children: [ ContentChildSchema ],
  order: { type: Number },
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now }
})

ContentChildSchema.add({
  children: [ ContentChildSchema ]
})

// 先创建模型,之后才定义父Schema的中间件
const ContentParentModel        = mongoose.model('Content', ContentParentSchema)

ContentChildSchema.post('save', (doc) => {
  console.log('ChildSchema: ' + doc)
})

ContentParentSchema.post('save', (doc) => {
  console.log('ParentSchema: ' + doc)
})

export default ContentParentModel

ContentController.js

ContentRoute.post('/', async (req, res) => {
  try {
    const page            = req.body.page
    const children        = req.body.children
    const content         = req.body.content

    const doc             = new ContentParentModel()

    doc.page              = page
    doc.children.push({ content: content })

    doc.save()

    return res.status(200).json({
      success: 'add content',
      message: 'Innhåll har lagts till.',
      data: doc
    })
  } catch(error) {
    return res.status(500).json({
      error: 'add content',
      message: 'Något gick fel med att lägga till innehåll.',
      errorData: error.message
    })
  }
})

问题原因

Mongoose的核心机制是:调用mongoose.model()创建模型时,会对当前的Schema进行编译,将Schema的结构、中间件等所有配置绑定到模型上。如果在模型创建完成后再给Schema添加中间件,这些新增的中间件不会被已编译的模型所应用。

你的代码中,父Schema的post('save')中间件是在ContentParentModel创建之后定义的,因此这个中间件没有被绑定到模型上,自然不会触发。而子Schema的中间件虽然也是在模型创建后定义,但嵌套文档的中间件触发逻辑不同,它会在父文档保存时单独处理子文档的中间件,所以子的能生效。

修复方案

将父Schema的post('save')中间件定义移到mongoose.model()调用之前,确保编译模型时中间件已经被添加到Schema中。

修改后的ContentModel.js关键部分

// 先定义所有中间件
ContentChildSchema.post('save', (doc) => {
  console.log('ChildSchema: ' + doc)
})

ContentParentSchema.post('save', (doc) => {
  console.log('ParentSchema: ' + doc)
})

// 再创建模型
const ContentParentModel        = mongoose.model('Content', ContentParentSchema)

export default ContentParentModel

另外,建议将doc.save()改为await doc.save(),因为save()是异步操作,不等待完成就返回响应可能会导致返回的数据不是最终保存到数据库的状态,同时也能正确捕获保存过程中的错误。

修改后的ContentController.js关键部分

// 等待save操作完成
await doc.save()

return res.status(200).json({
  success: 'add content',
  message: 'Innhåll har lagts till.',
  data: doc
})

验证

修改后重新运行代码,保存父文档时,控制台会同时输出父Schema和子Schema的日志,说明两个中间件都正常执行。

内容的提问来源于stack exchange,提问作者Fexell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 16:23:22