додайте поля create_at та updated_at до мангустних схем


166

Чи можна додати поля create_at та updated_at до схеми мангуста, без необхідності передавати їх у кожен виклик нового MyModel ()?

Поле create_at буде датою і додається лише при створенні документа. Поле updated_at буде оновлено новою датою кожного разу, коли в документі буде викликано Save ().

Я спробував це в своїй схемі, але поле не відображається, якщо я не докладно додаю його:

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

Я робив саме те, що ти робив, і це спрацювало. Використання мангусти 4.8.4. Можливо, це буде нова річ?
понедельник

1
це було з досить давно.
chovy

Так, подумав, що варто зазначити, що вищезгадане зараз працює.
понедельник

Відповіді:


132

Станом на Mongoose 4.0, тепер ви можете встановити на схемі параметр часових позначок, щоб Mongoose вирішував це для вас:

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

Ви можете змінити назву таких полів:

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

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


2
Погоджено, це найкращий варіант у Mongoose 4.0.
Тадд Гілз

258

ОНОВЛЕННЯ: (5 років потому)

Примітка. Якщо ви вирішили використовувати Kappa Architecture ( події Sourcing + CQRS ), то вам зовсім не потрібна оновлена ​​дата. Оскільки ваші дані - це непорушний журнал подій, що додається, вам потрібна лише дата створення створеної події. Схожа на архітектуру лямбда , описану нижче. Тоді стан вашої програми - це проекція журналу подій (отримані дані). Якщо ви отримаєте наступну подію про існуючу сутність, ви використовуєте дату створення цієї події як оновлену дату для вашої організації. Це загальноприйнята (і зазвичай неправильно зрозуміла) практика в системах міцеросервісу.

ОНОВЛЕННЯ: (4 роки пізніше)

Якщо ви використовуєте ObjectIdяк своє _idполе (що зазвичай буває), то все, що вам потрібно зробити, це:

let document = {
  updatedAt: new Date(),
}

Перегляньте мою оригінальну відповідь нижче про те, як отримати створену часову позначку з _idполя. Якщо вам потрібно використовувати ідентифікатори із зовнішньої системи, перевірте відповідь Романа Ррн Нестерова.

ОНОВЛЕННЯ: (через 2,5 роки)

Тепер ви можете використовувати опцію #timestamps з версією мангуста> = 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. Аналогічно, якщо ви хочете оновити документ - ви створюєте новий з відповідними оновленими полями, а решта полів копіюються. Потім для запиту цього документа ви отримаєте той, який має нову часову позначку або найвищу версію, яка є не "видалено" (thedeleted поле не визначене або помилкове`).

Незмінність даних гарантує налагодження ваших даних - ви можете простежити історію кожного документа. Ви також можете повернути до попередньої версії документа, якщо щось піде не так. Якщо ви їдете з такою архітектурою ObjectId.getTimestamp()- це все, що вам потрібно, і це не залежить від мангуста.


ОРИГІНАЛЬНИЙ ВІДПОВІДЬ:

Якщо ви використовуєте ObjectId як своє поле ідентичності, вам це created_atполе не потрібно . ObjectIds має метод, який називається getTimestamp().

ObjectId ("507c7f79bcf86cd7994f6c0e"). GetTimestamp ()

Це поверне такий результат:

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

Більше інформації тут Як витягти створену дату з Obgo ID Mongo

Для того, щоб додати 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();
});

3
Як це зробити в Mongoose / node.js?
Лабораторія зведення зебри

6
Про це варто знати, навіть якщо це рішення не звикає, дуже цікаве!
мимоволі

Але якщо я хочу передати створення в дату перегляду, мені знадобиться встановити для цього спеціальну змінну або передати ідентифікатор правильно?

3
Я вдячний за початкову відповідь, але прихильність до використання лямбда-архітектури також звучить як чудовий спосіб вирішити 5-кратний рівень мета-проблем і, можливо, ніколи не поставити, а не створити додаток CRUD та зробити його простим, якщо складність цього підходу справді не гарантована. Пам'ятайте, що ви пишете про MongoDB, який 'ледь' розгортається з початку, і ви виступаєте за новий запис кожного запису, який швидко вб'є Монго в будь-якому значущому масштабі. Перемістіть це до розділу Кассандра ...
Джон Кальвінер

1
Я насправді змінив свій дизайн бекенда для того, щоб виконувати м'які видалення замість справжніх делетів, завдяки інформації, наданій у цій відповіді. Це дає деякі глибші знання, які справді корисні.
Кенна

133

Ось що я закінчив робити:

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();
});

8
1. Збережіть поточний час у локальній варі та призначте його замість кожного разу виклику нової дати (), це переконається, що при першому проході create_at та updated_at мають однакове значення перевищення. 2. нова дата => нова дата ()
Шай Ерліхмен

13
Хочеться лише зазначити, що якщо ви використовуєте ObjectId, ви можете отримати звідти створений_at .... вам не потрібно окреме поле. ВиїздgetTimestamp()
Xerri

6
Іншим варіантом create_at може бути зміна моделі на -> created_at: {type: Дата, за замовчуванням: Date.now},
OscarVGG

1
@ajbraus Зробіть плагін для схеми
wlingke

2
також використовуйте Date.now()там, де це можливо, замість того, щоб new Dateшвидше, оскільки це статичний метод
karlkurzer

107

Використовуйте вбудований timestampsваріант для вашої схеми.

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

Це автоматично додасть createdAtі updatedAtполя до вашої схеми.

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


1
Потрібна версія мангусти> = 4.0
Дженсен

2
Я вважаю, що документи незрозумілі - це додає поля, але чи переконайтесь, що вони оновлюються під час кожного оновлення?
Людвік

загалом, createAt завжди зберігається лише один раз ... коли об’єкт створений. updatedAtоновлюється при кожному новому збереженні (коли змінено об'єкт)
codyc4321

1
Я отримав це "2016-12-07T11: 46: 46.066Z" .. Поясніть, будь ласка, формат часової позначки, як змінити часовий пояс ?? це прийняти часовий пояс сервера mongoDB ??
Mahesh K

@mcompeau, Дякую за відповідь! Я знаю, що це дальний постріл, але чи пам’ятаєте ви випадково, якщо поля, створені таким чином, можна використовувати як індекс?
manidos

29

Якщо використовувати update()абоfindOneAndUpdate()

з {upsert: true}варіантом

ви можете використовувати $setOnInsert

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

1
це працює в більшості бібліотек Монго. зміна прийнятої відповіді
чові

1
Якщо ви використовуєте _idполе Mogo за замовчуванням , воно вам не потрібно createdAt. Перегляньте мою відповідь нижче для отримання більш детальної інформації.
Павло Ніколов

1
... перевірити мій Оригінальний відповідь .
Павло Ніколов

25

Додати 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' }

2
Тепер, коли Mongoose робить все це для вас, я погоджуюся, що це найкраще рішення зараз.
Вінс Боудрен

Так, погоджуйся на це @VinceBowdren
Mr.spShuvo

8

Ось як я домігся, створивши та оновивши.

Всередині своєї схеми я додав створене та оновлене так:

   / **
     * Схема статті
     * /
    var ArticleSchema = нова схема ({
        створено: {
            тип: дата,
            за замовчуванням: Date.now
        },
        оновлено: {
            тип: дата,
            за замовчуванням: Date.now
        },
        назва: {
            тип: Рядок,
            за замовчуванням: '',
            обробка: правда,
            Потрібно: "Назва не може бути порожньою"
        },
        вміст: {
            тип: Рядок,
            за замовчуванням: '',
            обробка: правда
        },
        користувач: {
            тип: Schema.ObjectId,
            ref: "Користувач"
        }
    });

Потім у свій метод оновлення статті всередині контролера статті я додав:

/ **
     * Оновіть статтю
     * /
    export.update = функція (req, res) {
        var article = req.article;

        article = _.extend (стаття, req.body);
        article.set ("оновлено", Date.now ());

        Article.save (функція (помилка) {
            якщо (помилка) {
                повернути res.status (400) .send ({
                    повідомлення: errorHandler.getErrorMessage (помилка)
                });
            } else {
                res.json (стаття);
            }
        });
    };

Сміливі розділи представляють інтерес.



4

Ви можете використовувати timestampплагін, mongoose-troopщоб додати цю поведінку до будь-якої схеми.


3

Ви можете використовувати цей плагін дуже легко. З документів:

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'
});

2

ми можемо досягти цього, використовуючи також плагін схеми .

У 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);

2

У вашій схемі моделі просто додайте часові позначки атрибута та призначте йому значення true, як показано: -

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

Що це зробить?
chovy

Атрибут Timestamp додасть поля create_at та updated_at у кожен документ. Поле Created_at вказує час створення документа, а поле updated_at вказує час оновлення, якщо інше - час створення документа. Значення обох полів знаходиться у форматі часу ISO. Сподіваюся, це очистить ваші сумніви Чові.
Pavneet Kaur

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 }
});

Тепер ви можете використовувати це, щоб не було необхідності включати цю опцію в кожну таблицю


1

Моя версія мангусти - 4.10.2

Здається, лише гачок findOneAndUpdate- це робота

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

0

Використовуйте функцію для повернення обчисленого значення за замовчуванням:

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();
});

не потрібно Date.now()...default: Date.now()
завершувати

1
Я запускаю його у функцію, щоб я міг знущатися над «.now ()» у тестах. В іншому випадку він виконується лише один раз під час ініціалізації, і значення не може бути легко змінено.
orourkedd

1
Зауважте, що це default: Date.now()було б неправильно. Якщо що - то default: Date.now. Інакше всі ваші документи матимуть однакову
позначку

Мені подобається ваша default: Date.nowстратегія. набагато чистіше.
orourkedd

0

Я насправді роблю це ззаду

Якщо з оновленням все піде добре:

 // 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
      });
    });

0

Використовуйте 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


-2

Можна використовувати проміжне програмне забезпечення та віртуали . Ось приклад для вашого updated_atполя:

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

Коли це насправді встановиться? і чи збережеться це? Отже, 3 дні відтепер у нього все ще буде дата 3 дні тому?
chovy

у цьому випадку віртуальний буде викликатися щоразу, коли ви зміните задану властивість name. І так, воно повинно бути наполегливим.
zemirco

чи буде це працювати для всіх полів об’єкта Item? Я не впевнений, що це рішення робить те, що я хочу,
човен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.