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

如何在Mongoose中当超过expires_at时自动将expired字段设为true?

问题描述

我已经实现了投票(Poll)文档中expires_at字段的计算逻辑(基于创建时间和管理员设置的分钟级duration),现在需要实现:当当前时间超过expires_at时,自动将布尔类型的expired字段设为true。目前仅能在保存文档时触发expired的更新逻辑,不清楚如何让Mongoose在时间到达expires_at时自动触发更新。

现有代码如下:

const PollSchema = new mongoose.Schema({
  question: {
    type: String,
    required: true,
  },
  options: {
    type: Array,
    required: true,
  },
  expires_at: {
    type: Date,
  },
  expired: {
    type: Boolean,  
    default: false // how I can update this value to true when now > expires_at;
  },
  duration: {
    type: Number,
    required: true,
  },
});

PollSchema.pre('save', function (next) {
  const poll = this;
  poll.expired = expired(poll);
  next();
});
PollSchema.pre('save', function (next) {
  const poll = this;
  var now = new Date();
  poll.expires_at = now.setMinutes(now.getMinutes() + poll.duration);
  next();
});

// I am triggering this function on save, but I think it should be triggered when now > poll.expires_at;  

PollSchema.pre('save', function (next) {
  const poll = this;
  const now = new Date();
  poll.expired = now > poll.expires_at;
  next();
});

可行解决方案

1. 查询时动态计算(最简单推荐)

没必要把expired存在数据库里,每次查询时直接通过expires_at判断状态,或者用Mongoose虚拟字段实现:

// 定义虚拟字段,不存储到数据库,每次访问时实时计算
PollSchema.virtual('expired').get(function() {
  return new Date() > this.expires_at;
});

// 确保转换为JSON/对象时返回虚拟字段
PollSchema.set('toJSON', { virtuals: true });
PollSchema.set('toObject', { virtuals: true });

如果一定要把expired存在数据库,可以在查询前先批量更新符合条件的文档:

async function getPolls() {
  // 更新所有已过期但未标记的投票
  await Poll.updateMany(
    { expires_at: { $lt: new Date() }, expired: false },
    { $set: { expired: true } }
  );
  return Poll.find();
}

2. 定时任务主动扫描

用Node.js定时任务库(比如node-schedule)定期扫描数据库,主动更新过期文档:
首先安装依赖:

npm install node-schedule

然后编写定时任务:

const schedule = require('node-schedule');

// 每分钟执行一次扫描更新
schedule.scheduleJob('* * * * *', async () => {
  await Poll.updateMany(
    { expires_at: { $lt: new Date() }, expired: false },
    { $set: { expired: true } }
  );
});

这种方式能保证数据库里的expired字段实时同步,适合需要基于该字段做统计或查询过滤的场景。

3. 查询中间件自动触发更新

给find、findOne等查询方法添加预中间件,每次查询前自动更新过期文档:

PollSchema.pre(['find', 'findOne', 'findById'], async function(next) {
  // 批量更新已过期但未标记的文档
  await this.model.updateMany(
    { expires_at: { $lt: new Date() }, expired: false },
    { $set: { expired: true } }
  );
  next();
});

这样每次查询都会先同步过期状态,保证返回结果的准确性。

内容的提问来源于stack exchange,提问作者Yusuf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 02:01:10