如何阻止Mongoose save()覆盖自定义设置的updatedAt字段?
解决Mongoose save()覆盖手动设置的updatedAt字段问题
这个问题我之前也碰到过——因为你在Schema里启用了timestamps选项,Mongoose默认会在每次调用save()时自动把updatedAt刷新为当前时间,哪怕你手动设置过它的值。下面给你几个实用的解决方案:
1. 单次保存时临时禁用自动时间戳
这是最直接的临时处理方式,在调用save()的时候传入{ timestamps: false }选项,告诉Mongoose这次不要自动更新时间戳:
// 手动设置updatedAt之后,保存时加上timestamps: false参数 await applicant.save({ timestamps: false });
这样你手动设置的updatedAt就会被完整保留,不会被覆盖。适合只需要在个别测试用例或操作里跳过自动更新的场景。
2. 自定义时间戳更新逻辑(全局控制)
如果需要更灵活的全局规则——比如只有当updatedAt没有被手动修改时才自动更新,可以给Schema添加一个pre('save')钩子:
const DataSchema: Schema = new Schema({ user_name: { type: String, required: true }, uuid: { type: String, required: true }, status: { type: String, required: true, default: "unprocessed" }, request_origin: { type: String, required: true } }, { timestamps: { createdAt: "createdAt", updatedAt: "updatedAt" } }); // 添加pre-save钩子,判断是否手动修改过updatedAt DataSchema.pre('save', function(next) { // 如果已经手动修改过updatedAt,直接跳过自动更新逻辑 if (this.isModified('updatedAt')) { return next(); } // 否则保持默认的自动更新行为 this.updatedAt = new Date(); next(); });
这个钩子会在保存前检查updatedAt是否被手动改动过,如果是的话就不执行自动更新,完全保留你设置的值。
3. 用更新操作代替save()(测试场景适配)
在单元测试场景里,也可以直接用updateOne或findOneAndUpdate来设置字段,绕开save()的自动时间戳机制:
// 先创建基础文档 await DataModel.create({ "user_name": "user_notifying2rejected", "uuid": "10", "status": "notifying_user", "request_origin": "127.0.0.10" }); // 直接更新指定文档的updatedAt字段 await DataModel.updateOne( { uuid: "10" }, { updatedAt: new Date(new Date() - 2.592e+8) } );
这种方法适合不需要先实例化文档,直接修改数据库中字段的测试场景。
内容的提问来源于stack exchange,提问作者oneturkmen
相关产品推荐
相关产品推荐

