dodaj pola created_at i updated_at do schematów mangusty


166

Czy istnieje sposób na dodanie pól created_at i updated_at do schematu mangusty bez konieczności ich przekazywania za każdym razem, gdy wywoływana jest funkcja new MyModel ()?

Pole created_at byłoby datą i jest dodawane tylko podczas tworzenia dokumentu. Pole updated_at będzie aktualizowane nową datą za każdym razem, gdy wywoływana jest metoda save () w dokumencie.

Próbowałem tego w moim schemacie, ale pole nie pojawia się, chyba że dodam je w sposób dokładny:

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

Zrobiłem dokładnie to, co ty i zadziałało. Korzystanie z Mongoose 4.8.4. Może to coś nowego?
martinedwards

1
to było od jakiegoś czasu.
chovy

Tak, pomyślałem, że warto zauważyć, że powyższe działa teraz.
martinedwards

Odpowiedzi:


132

Począwszy od Mongoose 4.0, możesz teraz ustawić opcję znaczników czasu w schemacie, aby Mongoose zajął się tym za Ciebie:

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

Możesz zmienić nazwy pól używanych w następujący sposób:

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

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


2
Zgoda, to najlepsza opcja w Mongoose 4.0.
Tadd Giles

258

UPDATE: (5 lat później)

Uwaga: jeśli zdecydujesz się na korzystanie z architektury Kappa ( źródło zdarzeń + CQRS ), nie potrzebujesz w ogóle zaktualizowanej daty. Ponieważ Twoje dane są niezmiennym dziennikiem zdarzeń, który można tylko dopisać, potrzebujesz tylko daty utworzenia zdarzenia. Podobna do opisanej poniżej architektury lambda . W takim przypadku stan aplikacji jest projekcją dziennika zdarzeń (danych pochodnych). Jeśli otrzymasz kolejne zdarzenie dotyczące istniejącej encji, użyjesz daty utworzenia tego zdarzenia jako zaktualizowanej daty swojej encji. Jest to powszechnie stosowana (i często niezrozumiana) praktyka w systemach mikrousług.

UPDATE: (4 lata później)

Jeśli używasz ObjectIdjako swojego _idpola (co zwykle ma miejsce), wszystko, co musisz zrobić, to:

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

Sprawdź moją oryginalną odpowiedź poniżej, jak uzyskać utworzony znacznik czasu z _idpola. Jeśli potrzebujesz użyć identyfikatorów z systemu zewnętrznego, sprawdź odpowiedź Romana Rhrna Nesterova.

AKTUALIZACJA: (2,5 roku później)

Możesz teraz użyć opcji #timestamps z wersją mangusty> = 4.0.

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

Jeśli ustawisz sygnatury czasowe, przypisania mongoose createdAti updatedAtpola do schematu, przypisany typ to Date.

Możesz także określić nazwy zbiorów sygnatur czasowych:

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

Uwaga: jeśli pracujesz nad dużą aplikacją z krytycznymi danymi, powinieneś ponownie rozważyć aktualizację dokumentów. Radziłbym pracować z niezmiennymi danymi tylko do dołączania ( architektura lambda ). Oznacza to, że zezwalasz tylko na wstawianie. Aktualizacje i usuwanie nie powinny być dozwolone! Jeśli chcesz „usunąć” rekord, możesz łatwo wstawić nową wersję dokumentu z jakimś timestamp/ version wypełnionym, a następnie ustawić deletedpole na true. Podobnie, jeśli chcesz zaktualizować dokument - tworzysz nowy z zaktualizowanymi odpowiednimi polami i skopiowanymi pozostałymi polami, a następnie, aby odpytać ten dokument, otrzymasz dokument z najnowszym znacznikiem czasu lub najwyższą wersją, która jest nie „usunięte” (deleted pole jest niezdefiniowane lub fałszywe`).

Niezmienność danych zapewnia możliwość debugowania danych - możesz prześledzić historię każdego dokumentu. Możesz także przywrócić poprzednią wersję dokumentu, jeśli coś pójdzie nie tak. Jeśli wybierzesz taką architekturę, ObjectId.getTimestamp()to wszystko, czego potrzebujesz, i nie jest ona zależna od Mongoose.


ORYGINALNA ODPOWIEDŹ:

Jeśli używasz ObjectId jako pola tożsamości, nie potrzebujesz created_atpola. ObjectIds mają metodę o nazwie getTimestamp().

ObjectId ("507c7f79bcf86cd7994f6c0e"). GetTimestamp ()

To zwróci następujące dane wyjściowe:

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

Więcej informacji tutaj Jak wyodrębnić datę utworzenia z Mongo ObjectID

Aby dodać pole updated_at, musisz użyć tego:

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
Jak to robisz w Mongoose / node.js?
Zebra Propulsion Lab,

6
Warto to wiedzieć, nawet jeśli nie jest to rozwiązanie, które jest używane, bardzo interesujące!
nieświadomie

Ale jeśli chcę przekazać datę utworzenia do widoku, musiałbym ustawić specjalną zmienną do tego lub przekazać identyfikator, prawda?

3
Doceniam początkową odpowiedź, ale opowiadanie się za użyciem architektury lambda również brzmi jak świetny sposób na rozwiązanie 5-krotnych poziomów meta problemów i prawdopodobnie nigdy nie dostarcza, zamiast budować aplikację CRUD i utrzymywać ją w prostocie, chyba że złożoność tego podejścia jest naprawdę uzasadniona. Pamiętaj, że piszesz o MongoDB, który „ledwo” skaluje się na początku, i opowiadasz się za nowym rekordem dla każdego zapisu, który szybko zabije Mongo w dowolnej znaczącej skali. Przenieś to do sekcji Cassandra ...
John Culviner

1
Faktycznie zmieniłem projekt backendu, aby wykonywać miękkie usuwanie zamiast prawdziwych, dzięki informacjom podanym w tej odpowiedzi. Dostarcza głębszej wiedzy, która jest naprawdę przydatna.
Kenna

133

Oto, co ostatecznie zrobiłem:

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. Przechowuj bieżący czas w lokalnej zmiennej zmiennej i przypisuj go zamiast za każdym razem wywoływać new Date (), dzięki temu upewnisz się, że w pierwszym przejściu created_at i updated_at mają tę samą wartość excect. 2. nowa data => nowa data ()
Shay Erlichmen

13
Chciałbym tylko zaznaczyć, że jeśli używasz ObjectId, możesz pobrać stamtąd utworzony_at ... nie potrzebujesz osobnego pola. SprawdźgetTimestamp()
Xerri

6
Inną opcją dla created_at może być zmiana modelu na -> created_at: {type: Date, default: Date.now},
OscarVGG

1
@ajbraus Utwórz wtyczkę schematu
wlingke

2
w Date.now()miarę możliwości używaj również zamiast new Dateszybszego, ponieważ jest to metoda statyczna
karlkurzer

107

Użyj wbudowanej timestampsopcji dla swojego schematu.

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

To automatycznie doda createdAti updatedAtpola do schematu.

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


1
Wymaga wersji Mongoose> = 4.0
Jensen

2
Wydaje mi się, że dokumenty są niejasne - powoduje to dodanie pól, ale czy zapewnia również aktualizację przy każdej aktualizacji?
Ludwik

ogólnie rzecz biorąc, createdAt jest zawsze przechowywane tylko raz ... kiedy tworzony jest obiekt. updatedAtjest aktualizowany przy każdym nowym zapisie (po zmianie przedmiotu)
codyc4321

1
Mam to „2016-12-07T11: 46: 46.066Z” .. Czy mogę wyjaśnić format znacznika czasu, jak zmienić strefę czasową? czy zajmuje strefę czasową serwera mongoDB?
Mahesh K

@mcompeau, dziękuję za odpowiedź! Wiem, że to długa szansa, ale czy pamiętasz przypadkiem, czy pola utworzone w ten sposób mogą być używane jako indeks?
manidos

29

Jeśli używasz update()lubfindOneAndUpdate()

z {upsert: true}opcją

możesz użyć $setOnInsert

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

1
działa to w większości bibliotek mongo. zmiana na zaakceptowaną odpowiedź
chovy

1
Jeśli używasz domyślnego _idpola Mogo , nie potrzebujesz createdAtpola. Sprawdź moją odpowiedź poniżej, aby uzyskać więcej informacji.
Pavel Nikolov,

1
... sprawdź moją ORYGINALNĄ ODPOWIEDŹ .
Pavel Nikolov

25

Dodaj timestampsdo swojej Schematak wtedy createdAti updatedAtbędzie automatyczne generowanie dla Ciebie

var UserSchema = new Schema({
    email: String,
    views: { type: Number, default: 0 },
    status: Boolean
}, { timestamps: {} });

wprowadź opis obrazu tutaj
Ponadto można zmienić createdAt -> created_atprzez

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

2
Teraz, gdy Mongoose wykonuje całą tę pracę za Ciebie, zgadzam się, że jest to teraz najlepsze rozwiązanie.
Vince Bowdren

Tak, zgadzam się na to @VinceBowdren
Mr.spShuvo

8

W ten sposób osiągnąłem, tworząc i aktualizując.

Wewnątrz mojego schematu dodałem utworzony i zaktualizowany w następujący sposób:

   / **
     * Schemat artykułu
     * /
    var ArticleSchema = new Schema ({
        Utworzony: {
            typ: Data,
            domyślnie: Date.now
        },
        zaktualizowane: {
            typ: Data,
            domyślnie: Date.now
        },
        title: {
            typ: Sznurek,
            domyślna: '',
            wykończenie: prawda,
            wymagane: „Tytuł nie może być pusty”
        },
        zadowolony: {
            typ: Sznurek,
            domyślna: '',
            wykończenie: prawda
        },
        użytkownik: {
            type: Schema.ObjectId,
            ref: 'Użytkownik'
        }
    });

Następnie w mojej metodzie aktualizacji artykułu w kontrolerze artykułu dodałem:

/ **
     * Zaktualizuj artykuł
     * /
    exports.update = function (req, res) {
        var artykuł = req.article;

        artykuł = _.extend (artykuł, req.body);
        article.set ("zaktualizowany", Date.now ());

        article.save (function (err) {
            if (err) {
                return res.status (400) .send ({
                    komunikat: errorHandler.getErrorMessage (err)
                });
            } else {
                res.json (artykuł);
            }
        });
    };

Pogrubione sekcje to części, które Cię interesują.




3

Możesz bardzo łatwo korzystać z tej wtyczki . Z dokumentów:

var timestamps = require('mongoose-timestamp');
var UserSchema = new Schema({
    username: String
});
UserSchema.plugin(timestamps);
mongoose.model('User', UserSchema);
var User = mongoose.model('User', UserSchema)

A jeśli chcesz, ustaw również nazwy pól:

mongoose.plugin(timestamps,  {
  createdAt: 'created_at', 
  updatedAt: 'updated_at'
});

2

możemy to osiągnąć również za pomocą wtyczki schematu .

W helpers/schemaPlugin.jspliku

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

aw models/ItemSchema.jspliku:

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

W schemacie modelu po prostu dodaj sygnatury czasowe atrybutu i przypisz mu wartość true , jak pokazano: -

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

Co to zrobi?
chovy

Atrybut Timestamp doda pola created_at i updated_at w każdym dokumencie. Pole Created_at wskazuje czas utworzenia dokumentu, a pole updated_at wskazuje czas aktualizacji, jeśli w ogóle czas utworzenia dokumentu. Wartość obu pól jest w formacie czasu ISO. Mam nadzieję, że to rozwiąże twoje wątpliwości Chovy.
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 }
});

Teraz możesz tego użyć, aby nie trzeba było uwzględniać tej opcji w każdej tabeli


1

Moja wersja mangusty to 4.10.2

Wygląda na findOneAndUpdateto, że działa tylko hak

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

0

Użyj funkcji, aby zwrócić obliczoną wartość domyślną:

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

nie trzeba zawijać Date.now()funkcji po prostu:...default: Date.now()
karlkurzer

1
Zawijam go w funkcji, aby móc mockować '.now ()' w testach. W przeciwnym razie jest uruchamiany tylko raz podczas inicjalizacji, a wartości nie można łatwo zmienić.
orourkedd,

1
Zauważ, że default: Date.now()byłoby to złe. Jeśli już, to jest default: Date.now. W przeciwnym razie wszystkie Twoje dokumenty będą miały tę samą sygnaturę czasową: Godzina rozpoczęcia aplikacji;)
Max Truxa

Podoba mi się twoja default: Date.nowstrategia. dużo czystszy.
orourkedd

0

Właściwie robię to z tyłu

Jeśli wszystko pójdzie dobrze z aktualizacją:

 // 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

Sformatuj datę i godzinę za pomocą pakietu maszynowego-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
});

Pakiet maszynowy jest świetny z przejrzystym interfejsem API, w przeciwieństwie do ekspresowego lub ogólnego świata Javascript.


-2

Możesz użyć oprogramowania pośredniego i wirtualnych . Oto przykład dla twojego updated_atpola:

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

Kiedy to faktycznie zostanie ustawione? i czy będzie trwać? Czyli za 3 dni nadal będzie miała datę sprzed 3 dni?
chovy

wirtualny zostanie wywołany za każdym razem, gdy zmienisz daną właściwość, w tym przypadku name. I tak, powinno być trwałe.
zemirco

czy to zadziała dla wszystkich pól w obiekcie Item? Nie jestem pewien, czy to rozwiązanie robi to, czego chcę
chovy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.