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

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)

解决方案

核心问题分析

  1. 路由中动态添加pre('save')中间件的方式不可靠,模型导出后再修改Schema中间件可能不生效,需直接在模型定义文件中配置
  2. post('save')中间件中调用this.save()会触发无限循环,且无法直接获取字段变更前的值
  3. 需在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:35:27