タイムスタンプ
Mongoose スキーマは timestamps
オプションをサポートしています。timestamps: true
を設定すると、Mongoose は Date
型の 2 つのプロパティをスキーマに追加します。
createdAt
: このドキュメントが作成された時刻を表す日付updatedAt
: このドキュメントが最後に更新された時刻を表す日付
その後、Mongoose はドキュメントが最初に挿入されたときに createdAt
を設定し、save()
、updateOne()
、updateMany()
、findOneAndUpdate()
、update()
、replaceOne()
、または bulkWrite()
を使用してドキュメントを更新するたびに updatedAt
を更新します。
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
の更新を上書きします。
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
タイムスタンプが更新されます。
// `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
代替のプロパティ名
これらのドキュメントでは、常に createdAt
と updatedAt
を参照します。ただし、次の例に示すように、これらのプロパティ名を上書きできます。
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
}
});
タイムスタンプの無効化
save()
、updateOne()
、updateMany()
、findOneAndUpdate()
、update()
、replaceOne()
、および bulkWrite()
はすべて timestamps
オプションをサポートしています。特定の操作のタイムスタンプの設定をスキップするには、timestamps: false
を設定します。
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
はスキップします。
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
を自分で設定することで行えます。
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
サブドキュメントのタイムスタンプ
Mongoose はサブドキュメントにタイムスタンプを設定することもサポートしています。サブドキュメントの createdAt
と updatedAt
は、サブドキュメントが作成または更新された時刻を表すことに注意してください。上位レベルのドキュメントではありません。サブドキュメントを上書きすると 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
内部処理
タイムスタンプを使用したクエリの場合、Mongoose は更新クエリごとに 2 つのプロパティを追加します。
updatedAt
を$set
に追加createdAt
を$setOnInsert
に追加
たとえば、次のコードを実行した場合
mongoose.set('debug', true);
const userSchema = new Schema({
name: String
}, { timestamps: true });
const User = mongoose.model('User', userSchema);
await User.findOneAndUpdate({}, { name: 'test' });
Mongoose デバッグモードから次の出力が表示されます。
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' }}, {...})createdAt
の $setOnInsert
と updatedAt
の $set
に注目してください。MongoDB の $setOnInsert
演算子 は、新しいドキュメントだけが 追加挿入 されたときに更新を適用します。したがって、例えば、新しいドキュメントが作成された場合にのみ updatedAt
を設定したい場合は、updatedAt
タイムスタンプを無効にして、以下に示すように自分で設定することができます
await User.findOneAndUpdate({}, { $setOnInsert: { updatedAt: new Date() } }, {
timestamps: { createdAt: true, updatedAt: false }
});