Mongoose/MongoDB如何实现指定字段超时无变更自动标记inactive为true
实现方案
你需要先调整数据结构和添加Mongoose逻辑,具体步骤如下:
步骤1:调整Schema,新增目标字段更新时间戳
首先给你的Schema新增lastTargetFieldsModifiedAt字段,专门记录step、status、bool三个字段的最后更新时间:
const yourSchema = new mongoose.Schema({ step: String, status: String, bool: Boolean, startedAt: { type: Date, default: Date.now }, inactive: { type: Boolean, default: false }, // 新增字段,记录三个目标字段的最后更新时间 lastTargetFieldsModifiedAt: { type: Date, default: Date.now } }); // 新增联合索引,优化后续定时查询的速度 yourSchema.index({ lastTargetFieldsModifiedAt: 1, inactive: 1 });
步骤2:添加Mongoose中间件,自动更新时间戳
添加pre中间件,每次修改三个目标字段时自动刷新时间戳,同时重置inactive为false:
// 保存文档时的中间件 yourSchema.pre('save', function(next) { // 判断是否修改了三个目标字段中的任意一个 if (this.isModified('step') || this.isModified('status') || this.isModified('bool')) { this.lastTargetFieldsModifiedAt = new Date(); this.inactive = false; } next(); }); // 更新文档时的中间件,适配findOneAndUpdate、updateOne、updateMany等操作 yourSchema.pre(/^update/, function(next) { const updateOps = this.getUpdate(); const hasTargetUpdate = updateOps.$set && ( 'step' in updateOps.$set || 'status' in updateOps.$set || 'bool' in updateOps.$set ); if (hasTargetUpdate) { this.set({ lastTargetFieldsModifiedAt: new Date(), inactive: false }); } next(); });
步骤3:定期扫描更新inactive字段
最稳定的实现方式是用定时任务定期扫描符合条件的文档,批量更新inactive状态,示例用node-schedule实现:
const schedule = require('node-schedule'); const YourModel = mongoose.model('YourModel', yourSchema); // 配置定时规则,示例为每小时执行一次,可根据精度需求调整 schedule.scheduleJob('0 * * * *', async () => { // 自定义超时时长,示例为7天,单位毫秒 const EXPIRE_MS = 7 * 24 * 60 * 60 * 1000; await YourModel.updateMany( { lastTargetFieldsModifiedAt: { $lt: new Date(Date.now() - EXPIRE_MS) }, inactive: false }, { $set: { inactive: true } } ); });
方案说明
- 该方案兼容性好,支持所有MongoDB和Mongoose版本,运行稳定
- 定时周期越短,inactive状态更新越及时,可根据业务需求调整频率,只要提前建好联合索引,即使百万级数据查询也不会有性能问题
- 如果对实时性要求极高,可改用MongoDB变更流监听文档变更,为每个活跃文档设置独立超时定时器,服务重启时需重新初始化所有未超时的文档定时器即可
内容的提问来源于stack exchange,提问作者Kareem Etefy
相关产品推荐
相关产品推荐

