Добавить поля create_at и updated_at в схемы mongoose
Есть ли способ добавить поля create_at и updated_at в схему mongoose, не передавая их каждый раз, когда вызывается новый MyModel()?
Поле made_at будет датой и будет добавлено только при создании документа. Поле updated_at будет обновляться с новой датой всякий раз, когда save() вызывается для документа.
Я пробовал это в моей схеме, но поле не отображается, если я не добавлю его правильно:
var ItemSchema = new Schema({
name : { type: String, required: true, trim: true }
, created_at : { type: Date, required: true, default: Date.now }
});
22 ответа
Если использовать update()
или же findOneAndUpdate()
с {upsert: true}
вариант
ты можешь использовать $setOnInsert
var update = {
updatedAt: new Date(),
$setOnInsert: {
createdAt: new Date()
}
};
ОБНОВЛЕНИЕ: (5 лет спустя)
Примечание. Если вы решите использовать архитектуру Kappa (Event Sourcing + CQRS), вам не потребуется обновлять дату. Поскольку ваши данные являются неизменяемым журналом событий только для добавления, вам всегда нужна только дата создания события. Аналогично архитектуре Lambda, описанной ниже. Тогда состояние вашего приложения является проекцией журнала событий (производных данных). Если вы получите последующее событие о существующей сущности, вы будете использовать дату создания этого события в качестве обновленной даты для вашей сущности. Это широко используемая (и часто неправильно понимаемая) практика в системах микросервиса.
ОБНОВЛЕНИЕ: (4 года спустя)
Если вы используете ObjectId
как твой _id
поле (что обычно имеет место), тогда все, что вам нужно сделать, это:
let document = {
updatedAt: new Date(),
}
Проверьте мой оригинальный ответ ниже о том, как получить созданную временную метку из _id
поле. Если вам нужно использовать идентификаторы из внешней системы, то проверьте ответ Романа Рхрна Нестерова.
ОБНОВЛЕНИЕ: (2,5 года спустя)
Теперь вы можете использовать опцию #timestamps с версией mongoose>= 4.0.
let ItemSchema = new Schema({
name: { type: String, required: true, trim: true }
},
{
timestamps: true
});
Если установлены временные метки, Мангуста назначает createdAt
а также updatedAt
поля вашей схемы, назначенный тип Date
,
Вы также можете указать имена файлов временных меток:
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
Примечание. Если вы работаете с большим приложением с критически важными данными, вам следует пересмотреть вопрос об обновлении документов. Я бы посоветовал вам работать с неизменяемыми данными только для добавления ( лямбда-архитектура). Это означает, что вы разрешаете только вставки. Обновления и удаления не должны быть разрешены! Если вы хотите "удалить" запись, вы можете легко вставить новую версию документа с некоторыми
timestamp
/version
подал, а затем установитьdeleted
поле дляtrue
, Точно так же, если вы хотите обновить документ - вы создаете новый с обновленными соответствующими полями, а остальные поля копируются поверх. Затем для запроса этого документа вы получите тот, который имеет самую новую временную метку или самую высокую версию, которая является не "удалено" (deleted
поле не определено или ложно`).Неизменность данных гарантирует, что ваши данные можно отлаживать - вы можете отслеживать историю каждого документа. Вы также можете вернуться к предыдущей версии документа, если что-то пойдет не так. Если вы идете с такой архитектурой
ObjectId.getTimestamp()
это все, что вам нужно, и это не зависит от мангуста.
ОРИГИНАЛЬНЫЙ ОТВЕТ:
Если вы используете ObjectId в качестве поля идентификации, вам не нужно created_at
поле. ObjectIds имеет метод с именем 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();
});
Начиная с Mongoose 4.0, теперь вы можете установить опцию меток времени в схеме, чтобы Mongoose справился с этим за вас:
var thingSchema = new Schema({..}, { timestamps: true });
Вы можете изменить имя используемых полей следующим образом:
var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });
Это то, что я в итоге сделал:
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();
});
Используйте встроенный timestamps
вариант для вашей схемы.
var ItemSchema = new Schema({
name: { type: String, required: true, trim: true }
},
{
timestamps: true
});
Это автоматически добавит createdAt
а также updatedAt
поля для вашей схемы.
Добавлять timestamps
на ваш Schema
как это тогда createdAt
а также updatedAt
будет автоматически генерировать для вас
var UserSchema = new Schema({
email: String,
views: { type: Number, default: 0 },
status: Boolean
}, { timestamps: {} });
Также вы можете изменить createdAt -> created_at
от
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
В вашей :
const User = Schema(
{
firstName: { type: String, required: true },
lastName: { type: String, required: true },
password: { type: String, required: true }
},
{
timestamps: true
}
);
И после этого ваш
model
в
collection
будет так:
{
"_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"),
}
Для NestJ с Mongoose используйте это
@Schema({timestamps: true})
Вот как я добился, создав и обновив.
Внутри моей схемы я добавил созданное и обновленное примерно так:
/ ** * Схема статьи */ var ArticleSchema = новая схема ({ создано: { тип: дата, по умолчанию: Date.now }, обновлено: { тип: дата, по умолчанию: Date.now }, заглавие: { Тип: Строка, дефолт: '', отделка: правда, обязательно: "Заголовок не может быть пустым" }, содержание: { Тип: Строка, дефолт: '', отделка: есть }, пользователь: { тип: Schema.ObjectId, ref: 'Пользователь' } });
Затем в моем методе обновления статьи внутри контроллера статьи я добавил:
/ ** * Обновить статью * / exports.update = function (req, res) { var article = req.article; article = _.extend (article, req.body); article.set ("обновлено", Date.now ()); article.save (function (err) { if (err) { вернуть res.status(400).send({ сообщение: errorHandler.getErrorMessage(err) }); } еще { res.json(статья); } }); };
Разделы, выделенные жирным шрифтом, представляют интерес.
В схеме вашей модели просто добавьте метки времени атрибута и присвойте ему значение true, как показано:-
var ItemSchema = new Schema({
name : { type: String, required: true, trim: true },
},{timestamps : true}
);
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.
если вы используете nestjs и декоратор @Schema, вы можете добиться этого следующим образом:
@Schema({
timestamps: true,
})
Параметр timestamps указывает mongoose назначить поля createdAt и updatedAt вашей схеме. Назначенный тип - Дата.
По умолчанию имена полей createdAt и updatedAt.
Настройте имена полей, установив timestamps.createdAt и timestamps.updatedAt.
Мы можем достичь этого, используя также плагин схемы.
В 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);
Вы можете использовать timestamp
плагин из mongoose-troop
добавить это поведение в любую схему.
Вы можете использовать этот плагин очень легко. Из документов:
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'
});
Моя версия мангуста 4.10.2
Кажется только крючок findOneAndUpdate
это работа
ModelSchema.pre('findOneAndUpdate', function(next) {
// console.log('pre findOneAndUpdate ....')
this.update({},{ $set: { updatedAt: new Date() } });
next()
})
Начиная с mongo 3.6 вы можете использовать "поток изменений": https://emptysqua.re/blog/driver-features-for-mongodb-3-6/
Чтобы использовать его, вам нужно создать объект потока изменений с помощью запроса 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 должен работать как "набор реплик". Это также можно сделать в виде набора реплик с одним узлом (почти без изменений, чем при автономном использовании):
Запустите mongo как набор реплик: https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/
Конфигурация набора реплик по сравнению с автономным: Mongo DB - разница между автономным и 1-узловым набором реплик
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 }
});
Теперь вы можете использовать это, так что нет необходимости включать эту опцию в каждую таблицу
Я на самом деле делаю это в спину
Если все идет хорошо с обновлением:
// 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
});
});
Используйте функцию для возврата вычисленного значения по умолчанию:
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();
});
Используйте machinepack-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
});
Машинный пакет великолепен с понятным API, в отличие от экспресса или общего мира Javascript.
Вы можете использовать промежуточное программное обеспечение и виртуалы. Вот пример для вашего updated_at
поле:
ItemSchema.virtual('name').set(function (name) {
this.updated_at = Date.now;
return name;
});