时间戳
¥Timestamps
Mongoose 结构支持 timestamps
选项。如果你设置 timestamps: true
,Mongoose 会将两个 Date
类型的属性添加到你的结构中:
¥Mongoose schemas support a timestamps
option.
If you set timestamps: true
, Mongoose will add two properties of type Date
to your schema:
createdAt
:代表该文档创建时间的日期¥
createdAt
: a date representing when this document was createdupdatedAt
:表示本文档上次更新时间的日期¥
updatedAt
: a date representing when this document was last updated
然后,Mongoose 将在首次插入文档时设置 createdAt
,并在你使用 save()
、updateOne()
、updateMany()
、findOneAndUpdate()
、update()
、replaceOne()
或 bulkWrite()
更新文档时更新 updatedAt
。
¥Mongoose will then set createdAt
when the document is first inserted, and update updatedAt
whenever you update the document using save()
, updateOne()
, updateMany()
, findOneAndUpdate()
, update()
, replaceOne()
, or bulkWrite()
.
const userSchema = new Schema({ name: String }, { timestamps: true });
const User = mongoose.model('User', userSchema);
let doc = await User.create({ name: 'test' });
console.log(doc.createdAt); // 2022-02-26T16:37:48.244Z
console.log(doc.updatedAt); // 2022-02-26T16:37:48.244Z
doc.name = 'test2';
await doc.save();
console.log(doc.createdAt); // 2022-02-26T16:37:48.244Z
console.log(doc.updatedAt); // 2022-02-26T16:37:48.307Z
doc = await User.findOneAndUpdate({ _id: doc._id }, { name: 'test3' }, { new: true });
console.log(doc.createdAt); // 2022-02-26T16:37:48.244Z
console.log(doc.updatedAt); // 2022-02-26T16:37:48.366Z
createdAt
属性是不可变的,默认情况下,Mongoose 会覆盖任何用户指定的对 updatedAt
的更新。
¥The createdAt
property is immutable, and Mongoose overwrites any user-specified updates to updatedAt
by default.
let doc = await User.create({ name: 'test' });
console.log(doc.createdAt); // 2022-02-26T17:08:13.930Z
console.log(doc.updatedAt); // 2022-02-26T17:08:13.930Z
doc.name = 'test2';
doc.createdAt = new Date(0);
doc.updatedAt = new Date(0);
await doc.save();
// Mongoose blocked changing `createdAt` and set its own `updatedAt`, ignoring
// the attempt to manually set them.
console.log(doc.createdAt); // 2022-02-26T17:08:13.930Z
console.log(doc.updatedAt); // 2022-02-26T17:08:13.991Z
// Mongoose also blocks changing `createdAt` and sets its own `updatedAt`
// on `findOneAndUpdate()`, `updateMany()`, and other query operations
// **except** `replaceOne()` and `findOneAndReplace()`.
doc = await User.findOneAndUpdate(
{ _id: doc._id },
{ name: 'test3', createdAt: new Date(0), updatedAt: new Date(0) },
{ new: true }
);
console.log(doc.createdAt); // 2022-02-26T17:08:13.930Z
console.log(doc.updatedAt); // 2022-02-26T17:08:14.008Z
请记住,replaceOne()
和 findOneAndReplace()
会覆盖所有非 _id
属性,包括 createdAt
等不可变属性。调用 replaceOne()
或 findOneAndReplace()
将更新 createdAt
时间戳,如下所示。
¥Keep in mind that replaceOne()
and findOneAndReplace()
overwrite all non-_id
properties, including immutable properties like createdAt
.
Calling replaceOne()
or findOneAndReplace()
will update the createdAt
timestamp as shown below.
// `findOneAndReplace()` and `replaceOne()` without timestamps specified in `replacement`
// sets `createdAt` and `updatedAt` to current time.
doc = await User.findOneAndReplace(
{ _id: doc._id },
{ name: 'test3' },
{ new: true }
);
console.log(doc.createdAt); // 2022-02-26T17:08:14.008Z
console.log(doc.updatedAt); // 2022-02-26T17:08:14.008Z
// `findOneAndReplace()` and `replaceOne()` with timestamps specified in `replacement`
// sets `createdAt` and `updatedAt` to the values in `replacement`.
doc = await User.findOneAndReplace(
{ _id: doc._id },
{
name: 'test3',
createdAt: new Date('2022-06-01'),
updatedAt: new Date('2022-06-01')
},
{ new: true }
);
console.log(doc.createdAt); // 2022-06-01T00:00:00.000Z
console.log(doc.updatedAt); // 2022-06-01T00:00:00.000Z
备用属性名称
¥Alternate Property Names
出于这些文档的目的,我们将始终引用 createdAt
和 updatedAt
。但你可以覆盖这些属性名称,如下所示。
¥For the purposes of these docs, we'll always refer to createdAt
and updatedAt
.
But you can overwrite these property names as shown below.
const userSchema = new Schema({ name: String }, {
timestamps: {
createdAt: 'created_at', // Use `created_at` to store the created date
updatedAt: 'updated_at' // and `updated_at` to store the last updated date
}
});
禁用时间戳
¥Disabling Timestamps
save()
、updateOne()
、updateMany()
、findOneAndUpdate()
、update()
、replaceOne()
和 bulkWrite()
均支持 timestamps
选项。设置 timestamps: false
以跳过为该特定操作设置时间戳。
¥save()
, updateOne()
, updateMany()
, findOneAndUpdate()
, update()
, replaceOne()
, and bulkWrite()
all support a timestamps
option.
Set timestamps: false
to skip setting timestamps for that particular operation.
let doc = await User.create({ name: 'test' });
console.log(doc.createdAt); // 2022-02-26T23:28:54.264Z
console.log(doc.updatedAt); // 2022-02-26T23:28:54.264Z
doc.name = 'test2';
// Setting `timestamps: false` tells Mongoose to skip updating `updatedAt` on this `save()`
await doc.save({ timestamps: false });
console.log(doc.updatedAt); // 2022-02-26T23:28:54.264Z
// Similarly, setting `timestamps: false` on a query tells Mongoose to skip updating
// `updatedAt`.
doc = await User.findOneAndUpdate({ _id: doc._id }, { name: 'test3' }, {
new: true,
timestamps: false
});
console.log(doc.updatedAt); // 2022-02-26T23:28:54.264Z
// Below is how you can disable timestamps on a `bulkWrite()`
await User.bulkWrite([{
updateOne: {
filter: { _id: doc._id },
update: { name: 'test4' },
timestamps: false
}
}]);
doc = await User.findOne({ _id: doc._id });
console.log(doc.updatedAt); // 2022-02-26T23:28:54.264Z
你还可以将 timestamps
选项设置为对象以分别配置 createdAt
和 updatedAt
。例如,在下面的代码中,Mongoose 在 save()
上设置 createdAt
但跳过 updatedAt
。
¥You can also set the timestamps
option to an object to configure createdAt
and updatedAt
separately.
For example, in the below code, Mongoose sets createdAt
on save()
but skips updatedAt
.
const doc = new User({ name: 'test' });
// Tell Mongoose to set `createdAt`, but skip `updatedAt`.
await doc.save({ timestamps: { createdAt: true, updatedAt: false } });
console.log(doc.createdAt); // 2022-02-26T23:32:12.478Z
console.log(doc.updatedAt); // undefined
禁用时间戳还可以让你自己设置时间戳。例如,假设你需要更正文档的 createdAt
或 updatedAt
属性。你可以通过自行设置 timestamps: false
和 createdAt
来实现此目的,如下所示。
¥Disabling timestamps also lets you set timestamps yourself.
For example, suppose you need to correct a document's createdAt
or updatedAt
property.
You can do that by setting timestamps: false
and setting createdAt
yourself as shown below.
let doc = await User.create({ name: 'test' });
// To update `updatedAt`, do a `findOneAndUpdate()` with `timestamps: false` and
// `updatedAt` set to the value you want
doc = await User.findOneAndUpdate({ _id: doc._id }, { updatedAt: new Date(0) }, {
new: true,
timestamps: false
});
console.log(doc.updatedAt); // 1970-01-01T00:00:00.000Z
// To update `createdAt`, you also need to set `strict: false` because `createdAt`
// is immutable
doc = await User.findOneAndUpdate({ _id: doc._id }, { createdAt: new Date(0) }, {
new: true,
timestamps: false,
strict: false
});
console.log(doc.createdAt); // 1970-01-01T00:00:00.000Z
子文档的时间戳
¥Timestamps on Subdocuments
Mongoose 还支持在子文档上设置时间戳。请记住,子文档的 createdAt
和 updatedAt
代表子文档的创建或更新时间,而不是顶层文档。覆盖子文档也会覆盖 createdAt
。
¥Mongoose also supports setting timestamps on subdocuments.
Keep in mind that createdAt
and updatedAt
for subdocuments represent when the subdocument was created or updated, not the top level document.
Overwriting a subdocument will also overwrite createdAt
.
const roleSchema = new Schema({ value: String }, { timestamps: true });
const userSchema = new Schema({ name: String, roles: [roleSchema] });
const doc = await User.create({ name: 'test', roles: [{ value: 'admin' }] });
console.log(doc.roles[0].createdAt); // 2022-02-27T00:22:53.836Z
console.log(doc.roles[0].updatedAt); // 2022-02-27T00:22:53.836Z
// Overwriting the subdocument also overwrites `createdAt` and `updatedAt`
doc.roles[0] = { value: 'root' };
await doc.save();
console.log(doc.roles[0].createdAt); // 2022-02-27T00:22:53.902Z
console.log(doc.roles[0].updatedAt); // 2022-02-27T00:22:53.902Z
// But updating the subdocument preserves `createdAt` and updates `updatedAt`
doc.roles[0].value = 'admin';
await doc.save();
console.log(doc.roles[0].createdAt); // 2022-02-27T00:22:53.902Z
console.log(doc.roles[0].updatedAt); // 2022-02-27T00:22:53.909Z
引擎盖下
¥Under the Hood
对于带有时间戳的查询,Mongoose 为每个更新查询添加 2 个属性:
¥For queries with timestamps, Mongoose adds 2 properties to each update query:
将
updatedAt
添加到$set
¥Add
updatedAt
to$set
将
createdAt
添加到$setOnInsert
¥Add
createdAt
to$setOnInsert
例如,如果你运行以下代码:
¥For example, if you run the below code:
mongoose.set('debug', true);
const userSchema = new Schema({
name: String
}, { timestamps: true });
const User = mongoose.model('User', userSchema);
await User.findOneAndUpdate({}, { name: 'test' });
你将看到 Mongoose 调试结构的以下输出:
¥You'll see the below output from Mongoose debug mode:
Mongoose: users.findOneAndUpdate({}, { '$setOnInsert': { createdAt: new Date("Sun, 27 Feb 2022 00:26:27 GMT") }, '$set': { updatedAt: new Date("Sun, 27 Feb 2022 00:26:27 GMT"), name: 'test' }}, {...})请注意 $setOnInsert
对应 createdAt
,$set
对应 updatedAt
。仅当新文档为 upserted 时,MongoDB 的 $setOnInsert
运算符 才会应用更新。因此,例如,如果你只想在创建新文档时设置 updatedAt
,则可以禁用 updatedAt
时间戳并自行设置,如下所示:
¥Notice the $setOnInsert
for createdAt
and $set
for updatedAt
.
MongoDB's $setOnInsert
operator applies the update only if a new document is upserted.
So, for example, if you want to only set updatedAt
if a new document is created, you can disable the updatedAt
timestamp and set it yourself as shown below:
await User.findOneAndUpdate({}, { $setOnInsert: { updatedAt: new Date() } }, {
timestamps: { createdAt: true, updatedAt: false }
});