如何每日自动重置MongoDB Activity文档的totalFocusDay字段?
实现每日自动重置totalFocusDay的两种可行方案
方案一:惰性更新(推荐,无需额外维护定时任务)
这种思路是每次操作文档时自动检查是否需要重置,不用单独跑定时任务,对小项目或资源有限的场景更友好。
具体实现:
给Activity模型添加一个自定义静态方法,专门处理获取文档并自动重置的逻辑:
const mongoose = require("mongoose"); const activitySchema = new mongoose.Schema({ totalHours: { type: Number, default: 0 }, totalFocusDay: { type: Number, default: 0 }, totalActiveDay: { type: Number, default: 0 }, }, { timestamps: true, } ); // 自定义静态方法:获取文档前先检查并重置符合条件的记录 activitySchema.statics.getAndReset = async function(docId) { const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); // 先更新满足条件的文档:updatedAt早于24小时前的,重置totalFocusDay并更新时间 await this.updateOne( { _id: docId, updatedAt: { $lt: twentyFourHoursAgo } }, { $set: { totalFocusDay: 0 }, $currentDate: { updatedAt: true } } ); // 返回更新后的文档 return this.findById(docId); }; module.exports = mongoose.model("Activity", activitySchema);
之后业务代码里不用直接调用findById,改用这个自定义方法即可:
const Activity = require('./models/Activity'); // 获取目标文档并自动处理重置逻辑 const targetActivity = await Activity.getAndReset('目标文档ID');
如果想让所有findOne查询都自动触发检查,也可以用mongoose的前置中间件:
// 给findOne添加前置钩子,查询前自动重置符合条件的文档 activitySchema.pre('findOne', async function(next) { const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); // 对当前查询范围内的文档批量检查并重置 await this.model.updateMany( { ...this.getQuery(), updatedAt: { $lt: twentyFourHoursAgo } }, { $set: { totalFocusDay: 0 }, $currentDate: { updatedAt: true } } ); next(); });
方案二:定时批量更新(适合主动重置场景)
如果需要每天固定时间(比如凌晨0点)批量重置所有符合条件的文档,可以用node-schedule实现定时任务。
步骤:
- 安装依赖:
npm install node-schedule
- 编写定时任务脚本:
const schedule = require('node-schedule'); const Activity = require('./models/Activity'); // 每天凌晨0点执行重置任务(cron表达式格式:分 时 日 月 周) const resetJob = schedule.scheduleJob('0 0 * * *', async () => { const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); // 批量更新所有超过24小时未更新的文档 const updateResult = await Activity.updateMany( { updatedAt: { $lt: twentyFourHoursAgo } }, { $set: { totalFocusDay: 0 }, $currentDate: { updatedAt: true } } ); console.log(`每日重置完成:共修改${updateResult.modifiedCount}条文档`); }); console.log('每日重置任务已启动');
- 在项目启动时引入该脚本,确保定时任务持续运行。
关键细节提醒
- 使用
$currentDate更新updatedAt,能确保时间为MongoDB服务器的当前时间,避免客户端时间不一致的问题。 - 生产环境中,Node.js定时任务可能因服务重启中断,这种情况可以考虑使用MongoDB Atlas的定时触发器,稳定性更高。
内容的提问来源于stack exchange,提问作者Mohamed Ali
相关产品推荐
相关产品推荐

