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);
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);
分析与解决
-
默认值函数:
- 在定义
expire_date
的默认值时,直接使用new Date().setDate(new Date().getDate() + 3)
会导致日期计算错误。正确的做法是使用一个函数来动态生成默认值,如上面的default: function() { return new Date(Date.now() + 3 * 24 * 60 * 60 * 1000); }
。
- 在定义
-
时间计算:
- 确保在计算
expire_date
时,正确地添加了三天的时间。使用Date.now() + 3 * 24 * 60 * 60 * 1000
来计算三天后的日期。
- 确保在计算
-
查询和更新:
- 在
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 在处理默认值时可能会遇到一些时间处理上的问题。以下是一些改进建议:
-
避免使用函数作为默认值:在 Mongoose 中,直接使用函数来设置默认值可能会导致时间计算不准确。可以考虑将日期计算移到保存数据之前。
-
确保日期计算正确:确保日期计算是在正确的上下文中进行的。
以下是改进后的代码示例:
// 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);
解释
- 模型定义:在
DataSchema
中,我们将expire_date
的计算逻辑移至pre('save')
钩子中,确保在每次保存文档之前正确计算expire_date
。 - 间隔检查:在
setInterval
回调中,我们查询所有未过期的数据,并检查当前时间是否大于expire_date
。如果是,则将expired
字段设置为true
并保存文档。
通过这种方式,可以确保 expire_date
的计算是准确的,避免了日期提前的问题。