Mongoose中基于状态变更自动更新字段的中间件实现问题
MERN栈Mongoose中间件实现状态变更自动更新日期问题
需求说明
- 现有Lead Schema包含多字段,当
status字段从stageX变更为stageY时,需自动将文档的stageYdate字段(初始为null)更新为当前日期 - 逻辑需独立于现有路由与请求,通过模型/文档级中间件实现
- 已在模拟模型中尝试实现但未成功,相关代码如下:
模型定义代码
const mongoose = require("mongoose"); const Schema = mongoose.Schema; const ModelMiddlewareSchema = new mongoose.Schema({ stage: { type: String }, stageChangeDate:{ type: Date, } }); const ModelMiddleware = mongoose.model('ModelMiddleware', ModelMiddlewareSchema); //Tried using middleware here on "ModelMiddleware", didn't work :( module.exports = ModelMiddleware;
路由中尝试添加中间件的代码
const ModelMiddleware = require('../models/modelMiddlewareCheck'); const express = require('express'); const router = express.Router(); const logMiddleware = async function(next) { console.log(`Saving document ${this._id}`); this.stage = 'stage2' next(); }; ModelMiddleware.schema.pre('save', logMiddleware); router.put('/', async (req, res) => { try { console.log('req received as', req.body); const newDoc = new ModelMiddleware(); newDoc.stage = 'stage1'; await newDoc.save(); return res.status(200).send('stage1 created successfully'); } catch (err) { console.log(err); res.status(400).send('unsuccessful operation'); } }); module.exports = router;
期望实现的逻辑示例
const stage_initial = this.stage; const postStageCheck = function(next){ const stage_final = this.stage; if(stage_initial==='stage1' && stage_final==='stage2'){ this.stageChangeDate = new Date(); this.save() } next(); } ModelMiddleware.post('save', postStageCheck)
解决方案
核心问题分析
- 路由中动态添加
pre('save')中间件的方式不可靠,模型导出后再修改Schema中间件可能不生效,需直接在模型定义文件中配置 post('save')中间件中调用this.save()会触发无限循环,且无法直接获取字段变更前的值- 需在
pre('save')中间件中对比字段变更前后状态,同时覆盖findOneAndUpdate等批量更新场景
正确实现代码
修改后的模型定义文件
const mongoose = require("mongoose"); const Schema = mongoose.Schema; const ModelMiddlewareSchema = new mongoose.Schema({ stage: { type: String }, stageChangeDate: { type: Date, default: null } }); // 处理文档save场景的中间件 ModelMiddlewareSchema.pre('save', function(next) { // 检查stage字段是否修改,且从stage1变更为stage2 if (this.isModified('stage') && this.stage === 'stage2' && this._original?.stage === 'stage1') { this.stageChangeDate = new Date(); } next(); }); // 处理findByIdAndUpdate、updateOne等更新场景的中间件 ModelMiddlewareSchema.pre('findOneAndUpdate', function(next) { const update = this.getUpdate(); // 检查是否将stage更新为stage2 if (update.stage === 'stage2') { // 直接设置stageChangeDate为当前时间 this.set({ stageChangeDate: new Date() }); } next(); }); const ModelMiddleware = mongoose.model('ModelMiddleware', ModelMiddlewareSchema); module.exports = ModelMiddleware;
关键说明
isModified('stage'):判断stage字段是否被修改,避免无意义的逻辑执行this._original.stage:获取文档修改前的stage值(若mongoose版本不支持,可改用this.get('stage', { getters: false, virtuals: false })对比原始值)findOneAndUpdate中间件:save中间件不会触发findByIdAndUpdate等更新操作,需单独配置覆盖这类场景- 禁止在
post('save')中调用this.save(),会导致无限递归
内容的提问来源于stack exchange,提问作者Surviving_JS
相关产品推荐
相关产品推荐

