Nodejs 新增 schema 时, date 会乱跳

Nodejs 新增 schema 时, date 会乱跳

您好,想请问一下,最近在写个功能為使用者每次新增一笔资料后,还要设一个三天后过期的资料,最后再写个 setInterval 每一分钟检查一次,如果过期就标记并作其他后续处理。但不知為何,用 mongoose 设好的 schema 的日期有机会会产生跳掉的情形,而且是日期提前了,像今天 create_at 是 10 号,但 expire_date 却跑到 9 号去,造成资料一新增马上就过期,~~有时则是 create_at 提前了,~~请问这是怎么一回事?谢谢。

更正,create_at 的资料没问题,是 expire_date 算完后时间反而提前了,抱歉误导了。

node 版本是 0.8.23 mongoose: 3.8.2 mongodb: 2.0.4

//model

var Data = new Schema({ create_at: { type: Date, default: Date.now }, expire_date: { type: Date, default: (new Date().setDate(new Date().getDate() + 3)) }, expired: false });

mongoose.model(‘Data’, DataSchema);

// check out date

setInterval(function() { Data.find(function(err, data) { if(!err) { var length = data.length; for(var i =0; i < length; i++) { if(!data[i].expired && new Date() > data[i].expire_date) { data[i].expired = true; data[i].save(); } } } }); }, 60000);


8 回复

Node.js 新增 schema 时, date 会乱跳

您好,最近我在开发一个功能,需要为用户每次新增一条数据后,设置一个三天后过期的数据,并且每分钟通过 setInterval 检查一次,如果数据过期就进行标记和其他处理。但是遇到了一个问题,使用 Mongoose 定义的 schema 中的日期会出现异常,比如日期会提前,导致数据一新增马上就过期。

以下是问题的具体描述:

  • 使用 Mongoose 定义 schema 时,expire_date 会比预期的时间提前。
  • create_at 的日期没有问题,问题出在 expire_date 上。

以下是具体的代码示例和分析:

Model Definition

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// 定义 schema
var DataSchema = new Schema({
  create_at: { type: Date, default: Date.now },
  expire_date: { type: Date, default: function() { return new Date(Date.now() + 3 * 24 * 60 * 60 * 1000); } },
  expired: { type: Boolean, default: false }
});

// 注册模型
const Data = mongoose.model('Data', DataSchema);

module.exports = Data;

Check Out Expired Data

const Data = require('./models/Data'); // 引入定义的 model

// 每分钟检查一次
setInterval(function() {
  Data.find({ expired: false }, function(err, data) {
    if (!err) {
      data.forEach(item => {
        if (new Date() > item.expire_date) {
          item.expired = true;
          item.save();
        }
      });
    }
  });
}, 60000);

分析与解决

  1. 默认值函数

    • 在定义 expire_date 的默认值时,直接使用 new Date().setDate(new Date().getDate() + 3) 会导致日期计算错误。正确的做法是使用一个函数来动态生成默认值,如上面的 default: function() { return new Date(Date.now() + 3 * 24 * 60 * 60 * 1000); }
  2. 时间计算

    • 确保在计算 expire_date 时,正确地添加了三天的时间。使用 Date.now() + 3 * 24 * 60 * 60 * 1000 来计算三天后的日期。
  3. 查询和更新

    • setInterval 中,确保只查找未过期的数据,并且在更新数据时正确地设置 expired 属性。

通过以上改进,可以避免 expire_date 提前的问题,并确保数据的正确性。希望这些建议能帮助您解决问题。


new Date().getDate() + 3,三天之后不是这样写吧,假设已经是30号呢?建议先转成秒数,在次基础上加上24 * 3600 * 3,然后再转成日期。

这样可以的吧,超出来的日期Date会自动算到月份上

http://blog.darkthread.net/post-2013-06-25-json-date-timezone-issue.aspx

目前时光倒流能找到的原因最接近的大概是这个

总觉得你这句有问题 expire_date: { type: Date, default: (new Date().setDate(new Date().getDate() + 3)) }, 如果这个Schema需要的是一个Date的对象,那么default后面返回值是setDate的返回值。javascript里面setDate返回的只是调整过的一个毫秒数。

你这里create_at默认值是函数,而expire_date是值,在这个文件被require的时候(定义模型时)已经求值了! expire_date默认值改成:function() {return new Date().setDate(new Date().getDate() + 3);}试试。 更好的办法是在Schema加个动态方法,在真正创建文档的时候调用:

Data.methods.setExpire = function() {
    this.expire_date = new Date().setDate(new Date(this.create_at).getDate()+3)
}

原来如此,看来是我对 default 的理解有误,谢谢你的解释。

根据你的描述,问题可能出现在 expire_date 的计算方式上。Mongoose 在处理默认值时可能会遇到一些时间处理上的问题。以下是一些改进建议:

  1. 避免使用函数作为默认值:在 Mongoose 中,直接使用函数来设置默认值可能会导致时间计算不准确。可以考虑将日期计算移到保存数据之前。

  2. 确保日期计算正确:确保日期计算是在正确的上下文中进行的。

以下是改进后的代码示例:

// model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var DataSchema = new Schema({
  create_at: { type: Date, default: Date.now },
  expire_date: { type: Date },
  expired: { type: Boolean, default: false }
});

DataSchema.pre('save', function(next) {
  this.expire_date = new Date();
  this.expire_date.setDate(this.expire_date.getDate() + 3);
  next();
});

var Data = mongoose.model('Data', DataSchema);

module.exports = Data;
// main.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true });

var Data = require('./model');

setInterval(function() {
  Data.find({ expired: false }, function(err, data) {
    if (!err) {
      data.forEach(function(item) {
        if (new Date() > item.expire_date) {
          item.expired = true;
          item.save();
        }
      });
    } else {
      console.error(err);
    }
  });
}, 60000);

解释

  1. 模型定义:在 DataSchema 中,我们将 expire_date 的计算逻辑移至 pre('save') 钩子中,确保在每次保存文档之前正确计算 expire_date
  2. 间隔检查:在 setInterval 回调中,我们查询所有未过期的数据,并检查当前时间是否大于 expire_date。如果是,则将 expired 字段设置为 true 并保存文档。

通过这种方式,可以确保 expire_date 的计算是准确的,避免了日期提前的问题。

回到顶部