在猫鼬模式中添加created_at和updated_at字段

是否有一种方法可以将created_at和updated_at字段添加到猫鼬模式中,而不必在每次调用new MyModel()时传递它们?

created_at字段将是一个日期,仅在创建文档时添加。 每当在文档上调用save()时,updated_at字段将被更新为新的日期

我已经在我的模式中尝试了这一点,但除非我显式地添加它,否则字段不会显示:

var ItemSchema = new Schema({
name    : { type: String, required: true, trim: true },
created_at    : { type: Date, required: true, default: Date.now }
});
237820 次浏览

你可以使用中间件虚拟。下面是updated_at字段的示例:

ItemSchema.virtual('name').set(function (name) {
this.updated_at = Date.now;
return name;
});

这就是我最后做的:

var ItemSchema = new Schema({
name    : { type: String, required: true, trim: true }
, created_at    : { type: Date }
, updated_at    : { type: Date }
});




ItemSchema.pre('save', function(next){
now = new Date();
this.updated_at = now;
if ( !this.created_at ) {
this.created_at = now;
}
next();
});

你可以使用mongoose-trooptimestamp插件将此行为添加到任何模式。

更新:(5年后)

注意:如果你决定使用Kappa架构 (事件来源+ CQRS),那么你根本不需要更新日期。由于您的数据是一个不可变的、只能追加的事件日志,因此您只需要事件创建日期。类似于下面描述的λ架构。然后,应用程序状态是事件日志(派生数据)的投影。如果您收到关于现有实体的后续事件,那么您将使用该事件的创建日期作为实体的更新日期。这是微服务系统中常用(也常被误解)的实践。

更新:(4年后)

如果你使用ObjectId作为你的_id字段(通常是这样),那么你所需要做的就是:

let document = {
updatedAt: new Date(),
}
检查我下面关于如何从_id字段获得创建的时间戳的原始答案。 如果你需要使用外部系统的id,那么检查Roman Rhrn Nesterov的答案

更新:(2.5年后)

你现在可以在猫鼬版本>= 4.0中使用#时间戳选项。

let ItemSchema = new Schema({
name: { type: String, required: true, trim: true }
},
{
timestamps: true
});

如果设置了时间戳,mongoose将createdAtupdatedAt字段分配给你的模式,分配的类型是Date

你也可以指定时间戳字段的名称:

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
如果你正在处理一个包含关键数据的大型应用程序,你应该重新考虑更新你的文档。我建议你使用不可变的,只能追加的数据(λ架构)。这意味着 你只允许插入。更新和删除不应该是 允许!如果你想“删除”一条记录,你可以很容易地 用一些timestamp/version插入文档的新版本 然后将deleted字段设置为true。类似的,如果你想 要更新文档-您可以使用适当的 字段更新,其余字段复制。然后为了 查询此文档,您将获得具有最新时间戳的文档或 未“删除”的最高版本(deleted字段未定义或为假`)

数据不变性确保您的数据是可调试的-您可以跟踪 每个文件的历史。您也可以回退到上一级 如果出现错误,文档的版本。如果你选择这样的 architecture ObjectId.getTimestamp()是你所需要的,但它不是 猫鼬依赖。< / p >


最初的回答:

如果你使用ObjectId作为你的标识字段,你不需要created_at字段。objectid有一个叫做getTimestamp()的方法。

ObjectId("507c7f79bcf86cd7994f6c0e").getTimestamp()

这将返回以下输出:

ISODate("2012-10-15T21:26:17Z")

更多信息在这里我如何提取一个Mongo ObjectID创建的日期

为了添加updated_at字段,你需要使用这个:

var ArticleSchema = new Schema({
updated_at: { type: Date }
// rest of the fields go here
});


ArticleSchema.pre('save', function(next) {
this.updated_at = Date.now();
next();
});

如果使用update()findOneAndUpdate()

{upsert: true}选项

你可以使用$setOnInsert

var update = {
updatedAt: new Date(),
$setOnInsert: {
createdAt: new Date()
}
};

这就是我创造和更新的方式。

在我的模式中,我像这样添加了创建和更新:

/**
* Article Schema
*/
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
updated: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});

然后在文章控制器内的文章更新方法中添加:

/**
* Update a article
*/
exports.update = function(req, res) {
var article = req.article;


article = _.extend(article, req.body);
article.set("updated", Date.now());


article.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(article);
}
});
};

粗体部分是我们感兴趣的部分。

你可以很容易地使用这个插件

var timestamps = require('mongoose-timestamp');
var UserSchema = new Schema({
username: String
});
UserSchema.plugin(timestamps);
mongoose.model('User', UserSchema);
var User = mongoose.model('User', UserSchema)

如果你愿意,还可以设置字段的名称:

mongoose.plugin(timestamps,  {
createdAt: 'created_at',
updatedAt: 'updated_at'
});

从Mongoose 4.0开始,你现在可以在Schema上设置一个时间戳选项,让Mongoose为你处理这个问题:

var thingSchema = new Schema({..}, { timestamps: true });

你可以像这样更改字段的名称:

var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });

时间戳< a href = " http://mongoosejs.com/docs/guide.html " > < / > http://mongoosejs.com/docs/guide.html时间戳

使用函数返回计算出的默认值:

var ItemSchema = new Schema({
name: {
type: String,
required: true,
trim: true
},
created_at: {
type: Date,
default: function(){
return Date.now();
}
},
updated_at: {
type: Date,
default: function(){
return Date.now();
}
}
});


ItemSchema.pre('save', function(done) {
this.updated_at = Date.now();
done();
});

为你的Schema使用内置的timestamps选项。

var ItemSchema = new Schema({
name: { type: String, required: true, trim: true }
},
{
timestamps: true
});

这将自动将createdAtupdatedAt字段添加到你的模式中。

时间戳< a href = " http://mongoosejs.com/docs/guide.html " > < / > http://mongoosejs.com/docs/guide.html时间戳

我们也可以通过使用模式插件来实现这一点。

helpers/schemaPlugin.js文件中

module.exports = function(schema) {


var updateDate = function(next){
var self = this;
self.updated_at = new Date();
if ( !self.created_at ) {
self.created_at = now;
}
next()
};
// update date for bellow 4 methods
schema.pre('save', updateDate)
.pre('update', updateDate)
.pre('findOneAndUpdate', updateDate)
.pre('findByIdAndUpdate', updateDate);
};

models/ItemSchema.js文件中:

var mongoose = require('mongoose'),
Schema   = mongoose.Schema,
SchemaPlugin = require('../helpers/schemaPlugin');


var ItemSchema = new Schema({
name    : { type: String, required: true, trim: true },
created_at    : { type: Date },
updated_at    : { type: Date }
});
ItemSchema.plugin(SchemaPlugin);
module.exports = mongoose.model('Item', ItemSchema);
const mongoose = require('mongoose');
const config = require('config');
const util = require('util');


const Schema = mongoose.Schema;
const BaseSchema = function(obj, options) {
if (typeof(options) == 'undefined') {
options = {};
}
if (typeof(options['timestamps']) == 'undefined') {
options['timestamps'] = true;
}


Schema.apply(this, [obj, options]);
};
util.inherits(BaseSchema, Schema);


var testSchema = new BaseSchema({
jsonObject: { type: Object }
, stringVar : { type: String }
});

现在您可以使用这个选项,这样就不需要在每个表中都包含这个选项

像这样将timestamps添加到你的Schema中,那么createdAtupdatedAt将自动为你生成

var UserSchema = new Schema({
email: String,
views: { type: Number, default: 0 },
status: Boolean
}, { timestamps: {} });
< p > enter image description here < br > 你也可以通过

来改变createdAt -> created_at
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

我的猫鼬版本是4.10.2

似乎只有钩子findOneAndUpdate是工作的

ModelSchema.pre('findOneAndUpdate', function(next) {
// console.log('pre findOneAndUpdate ....')
this.update({},{ $set: { updatedAt: new Date() } });
next()
})

我在后面做了这个

如果更新一切顺利:

 // All ifs passed successfully. Moving on the Model.save
Model.lastUpdated = Date.now(); // <------ Now!
Model.save(function (err, result) {
if (err) {
return res.status(500).json({
title: 'An error occured',
error: err
});
}
res.status(200).json({
message: 'Model Updated',
obj: result
});
});

使用machinpack -datetime格式化日期时间。

tutorialSchema.virtual('createdOn').get(function () {
const DateTime = require('machinepack-datetime');
let timeAgoString = "";
try {
timeAgoString = DateTime.timeFrom({
toWhen: DateTime.parse({
datetime: this.createdAt
}).execSync(),
fromWhen: new Date().getTime()
}).execSync();
} catch(err) {
console.log('error getting createdon', err);
}
return timeAgoString; // a second ago
});

Machine pack非常出色,具有清晰的API,不像express或一般的Javascript世界。

var ItemSchema = new Schema({
name : { type: String, required: true, trim: true }
});


ItemSchema.set('timestamps', true); // this will add createdAt and updatedAt timestamps

文档:https://mongoosejs.com/docs/guide.html#timestamps

在你的模型模式中,只需添加一个属性timestamps,并将值true赋给它,如下所示

var ItemSchema = new Schema({
name :  { type: String, required: true, trim: true },
},{timestamps : true}
);
从mongo 3.6开始,你可以使用'change stream': https://emptysqua.re/blog/driver-features-for-mongodb-3-6/#change-streams < / p >

要使用它,你需要通过'watch'查询创建一个变更流对象,对于每个变更,你可以做任何你想做的事情…

python的解决方案:

def update_at_by(change):
update_fields = change["updateDescription"]["updatedFields"].keys()
print("update_fields: {}".format(update_fields))


collection = change["ns"]["coll"]
db = change["ns"]["db"]
key = change["documentKey"]


if len(update_fields) == 1 and "update_at" in update_fields:
pass  # to avoid recursion updates...
else:
client[db][collection].update(key, {"$set": {"update_at": datetime.now()}})




client = MongoClient("172.17.0.2")
db = client["Data"]


change_stream = db.watch()


for change in change_stream:
print(change)
update_ts_by(change)
注意,要使用change_stream对象,你的mongodb实例应该作为'replica set'运行。 它也可以作为一个1节点的副本集(几乎没有变化,然后独立使用):

运行mongo作为副本集: https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/ < / p >

副本集配置vs单机: Mongo DB -独立和放大器之间的区别;单节点副本集 < / p >

对于带有Mongoose的NestJs,使用这个

@Schema({timestamps: true})

如果你使用nestjs和@Schema装饰器,你可以实现这样的效果:

@Schema({
timestamps: true,
})

时间戳选项告诉猫鼬将createdAt和updatedAt字段分配给你的模式。分配的类型是Date。

默认情况下,字段的名称是createdAt和updatedAt。

通过设置时间戳自定义字段名。createdAt和timestamp . updatedat。

在你的model中:

const User = Schema(
{
firstName: { type: String, required: true },
lastName: { type: String, required: true },
password: { type: String, required: true }
},
{
timestamps: true
}
);

在此之后,你在collection中的model将像这样:

{
"_id" : ObjectId("5fca632621100c230ce1fb4b"),
"firstName" : "first",
"lastName" : "last",
"password" : "$2a$15$Btns/B28lYIlSIcgEKl9eOjxOnRjJdTaU6U2vP8jrn3DOAyvT.6xm",
"createdAt" : ISODate("2020-12-04T16:26:14.585Z"),
"updatedAt" : ISODate("2020-12-04T16:26:14.585Z"),
}