Добавить поля 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' } });

http://mongoosejs.com/docs/guide.html

Это то, что я в итоге сделал:

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 поля для вашей схемы.

http://mongoosejs.com/docs/guide.html

Добавлять 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;
});
Другие вопросы по тегам