aggiungere i campi Created_at e Updated_at agli schemi di mangusta


166

C'è un modo per aggiungere i campi create_at e updated_at a uno schema mongoose, senza doverli passare ogni volta che viene chiamato il nuovo MyModel ()?

Il campo Created_at sarebbe una data e aggiunto solo quando viene creato un documento. Il campo updated_at verrebbe aggiornato con una nuova data ogni volta che save () viene chiamato su un documento.

Ho provato questo nel mio schema, ma il campo non viene visualizzato se non lo aggiungo in modo esplicito:

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

Ho fatto esattamente quello che hai fatto e ha funzionato. Usando Mongoose 4.8.4. Potrebbe essere una cosa nuova?
Martinedwards,

1
questo era di un po 'di tempo fa.
amante

Sì, ho pensato che valesse la pena notare che ora sopra funziona.
martinedwards

Risposte:


132

A partire da Mongoose 4.0 è ora possibile impostare un'opzione timestamp sullo Schema per fare in modo che Mongoose gestisca questo per te:

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

È possibile modificare il nome dei campi utilizzati in questo modo:

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

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


2
D'accordo, questa è l'opzione migliore in Mongoose 4.0.
Tadd Giles,

258

AGGIORNAMENTO: (5 anni dopo)

Nota: se si decide di utilizzare Kappa Architecture ( Event Sourcing + CQRS ), non è necessario aggiornare la data. Dato che i tuoi dati sono un registro eventi immutabile e solo di append, hai sempre e solo bisogno della data di creazione dell'evento. Simile all'architettura Lambda , descritta di seguito. Quindi lo stato dell'applicazione è una proiezione del registro eventi (dati derivati). Se ricevi un evento successivo sull'entità esistente, utilizzerai la data di creazione dell'evento come data aggiornata per la tua entità. Questa è una pratica comunemente usata (e comunemente fraintesa) nei sistemi di microservizio.

AGGIORNAMENTO: (4 anni dopo)

Se usi ObjectIdcome _idcampo (che di solito è il caso), allora tutto ciò che devi fare è:

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

Controlla la mia risposta originale qui sotto su come ottenere il timestamp creato dal _idcampo. Se devi usare gli ID da un sistema esterno, controlla la risposta di Roman Rhrn Nesterov.

AGGIORNAMENTO: (2,5 anni dopo)

Ora puoi usare l' opzione #timestamps con la versione mongoose> = 4.0.

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

Se imposta timestamp, assegnazioni di mangusta createdAte updatedAtcampi al tuo schema, il tipo assegnato è Date.

Puoi anche specificare i nomi dei file di data e ora:

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

Nota: se stai lavorando su una grande applicazione con dati critici, dovresti riconsiderare l'aggiornamento dei tuoi documenti. Ti consiglierei di lavorare con dati immutabili, di sola aggiunta ( architettura lambda ). Ciò significa che permetti solo inserti. Aggiornamenti ed eliminazioni non dovrebbero essere consentiti! Se si desidera "eliminare" un record, è possibile inserire facilmente una nuova versione del documento con alcuni timestamp/ version archiviati e quindi impostare un deletedcampo su true. Allo stesso modo, se si desidera aggiornare un documento, ne si crea uno nuovo con i campi appropriati aggiornati e il resto dei campi copiati. Quindi, per interrogare questo documento, si otterrebbe quello con il timestamp più recente o la versione più alta che è non "cancellato" (ildeleted campo non definito o falso`).

L'immutabilità dei dati garantisce che i tuoi dati siano debuggabili: puoi tracciare la cronologia di ogni documento. Puoi anche ripristinare la versione precedente di un documento se qualcosa va storto. Se vai con una tale architettura ObjectId.getTimestamp()è tutto ciò di cui hai bisogno e non dipende da Mongoose.


RISPOSTA ORIGINALE:

Se si utilizza ObjectId come campo identità non è necessario il created_atcampo. Gli ObjectId hanno un metodo chiamato getTimestamp().

ObjectId ( "507c7f79bcf86cd7994f6c0e"). GetTimestamp ()

Ciò restituirà il seguente output:

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

Maggiori informazioni qui Come posso estrarre la data di creazione da un Mongo ObjectID

Per aggiungere l' updated_atarchivio è necessario utilizzare questo:

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
Come si fa in Mongoose / node.js?
Zebra Propulsion Lab

6
Vale la pena sapere anche se non è la soluzione che viene utilizzata, molto interessante!
inconsapevole il

Ma se voglio passare la creazione alla data alla vista, dovrei impostare una variabile speciale per questo, o passare l'id giusto?

3
Apprezzo la risposta iniziale, ma la promozione dell'utilizzo dell'architettura lambda suona anche come un ottimo modo per risolvere 5 livelli di meta problemi e probabilmente non fornire mai piuttosto che creare l'app CRUD e mantenerla semplice a meno che la complessità di questo approccio non sia veramente giustificata. Ricorda che stai pubblicando post su MongoDB che per iniziare "a malapena" si ridimensiona e stai sostenendo un nuovo record per ogni scrittura che ucciderà rapidamente Mongo su qualsiasi scala significativa.
Spostalo

1
In realtà ho cambiato il mio design di backend al fine di eseguire eliminazioni soft al posto di eliminazioni reali, grazie alle informazioni fornite in questa risposta. Fornisce alcune conoscenze più profonde che sono davvero utili.
Kenna

133

Questo è quello che ho finito per fare:

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. Memorizza l'ora corrente in una var locale e assegnala invece di ogni volta chiamando una nuova Data (), questo assicurerà che al primo passaggio create_at e updated_at abbiano lo stesso valore di excect. 2. nuova data => nuova data ()
Shay Erlichmen,

13
Vorrei solo sottolineare che se si utilizza ObjectId, è possibile ottenere il create_at da lì .... non è necessario un campo separato. getTimestamp()
Dai

6
Un'altra opzione per Created_at potrebbe essere quella di cambiare il modello in -> Created_at: {type: Date, default: Date.now},
OscarVGG

1
@ajbraus Crea un plug-in di schema
wlingke,

2
usa anche Date.now()dove possibile invece del new Datesuo più veloce in quanto è un metodo statico
karlkurzer

107

Utilizzare l' timestampsopzione integrata per lo schema.

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

Ciò aggiungerà automaticamente campi createdAte updatedAtal tuo schema.

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


1
Richiede la versione della mangusta> = 4.0
Jensen,

2
Trovo i documenti poco chiari: questo aggiunge i campi, ma assicura anche che siano aggiornati ad ogni aggiornamento?
Ludwik,

generalmente, CreatedAt viene sempre memorizzato solo una volta ... quando viene creato l'oggetto. updatedAtviene aggiornato ad ogni nuovo salvataggio (quando l'oggetto obj viene cambiato)
codyc4321

1
Ho ottenuto questo "2016-12-07T11: 46: 46.066Z" .. Potresti per favore spiegare il formato del timestamp, come cambiare il fuso orario ?? è prendere il fuso orario del server mongoDB ??
Mahesh K,

@mcompeau, grazie per la risposta! So che è un colpo lungo, ma ricordi per caso se i campi creati in questo modo possono essere usati come indice?
manidos,

29

Se usare update()ofindOneAndUpdate()

con {upsert: true}opzione

Puoi usare $setOnInsert

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

1
funziona nella maggior parte delle librerie di mongo. cambiando in risposta accettata
chovy

1
Se stai utilizzando il _idcampo predefinito di Mogo , non hai bisogno di un createdAtcampo. Controlla la mia risposta qui sotto per maggiori dettagli.
Pavel Nikolov,

1
... controlla la mia RISPOSTA ORIGINALE .
Pavel Nikolov il

25

Aggiungi timestampsa Schemaquesto quindi quindi createdAte updatedAtgenererà automaticamente per te

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

inserisci qui la descrizione dell'immagine
Inoltre puoi cambiare createdAt -> created_atdi

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

2
Ora che Mongoose fa tutto questo lavoro per te, sono d'accordo che questa è la soluzione migliore ora.
Vince Bowdren,

Sì, d'accordo su quel @VinceBowdren
Mr.spShuvo

8

È così che ho realizzato dopo aver creato e aggiornato.

Nel mio schema ho aggiunto il creato e aggiornato in questo modo:

   / **
     * Schema dell'articolo
     * /
    var ArticleSchema = new Schema ({
        creato: {
            tipo: data,
            impostazione predefinita: Date.now
        },
        aggiornato: {
            tipo: data,
            impostazione predefinita: Date.now
        },
        titolo: {
            tipo: stringa,
            predefinito: '',
            assetto: vero,
            richiesto: "Il titolo non può essere vuoto"
        },
        contenuto: {
            tipo: stringa,
            predefinito: '',
            assetto: vero
        },
        utente: {
            tipo: Schema.ObjectId,
            ref: 'Utente'
        }
    });

Quindi nel mio metodo di aggiornamento dell'articolo all'interno del controller dell'articolo ho aggiunto:

/ **
     * Aggiorna un articolo
     * /
    exports.update = function (req, res) {
        var articolo = req.article;

        articolo = _.extend (articolo, req.body);
        article.set ("aggiornato", Date.now ());

        article.save (function (err) {
            if (err) {
                return res.status (400) .send ({
                    messaggio: errorHandler.getErrorMessage (err)
                });
            } altro {
                res.json (articolo);
            }
        });
    };

Le sezioni in grassetto sono le parti di interesse.



4

È possibile utilizzare il timestampplug-in di mongoose-troopper aggiungere questo comportamento a qualsiasi schema.


3

Puoi usare questo plugin molto facilmente. Dai documenti:

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

E imposta anche il nome dei campi se desideri:

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

2

possiamo raggiungere questo obiettivo utilizzando anche il plug-in dello schema .

Nel helpers/schemaPlugin.jsfile

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

e in models/ItemSchema.jsarchivio:

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

Nello schema del modello, basta aggiungere un timestamp di un attributo e assegnargli un valore vero come mostrato: -

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

Cosa farà questo?
Chovy

L'attributo Timestamp aggiungerà i campi create_at e updated_at in ciascun documento. Il campo Created_at indica l'ora di creazione del documento e il campo updated_at indica l'ora di aggiornamento se presente l'ora di creazione del documento. Il valore di entrambi i campi è in formato ISO. Spero che questo chiarisca i tuoi dubbi Chovy.
Pavneet Kaur il

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

Ora puoi usarlo, in modo che non sia necessario includere questa opzione in ogni tabella


1

La mia versione di mangusta è la 4.10.2

Sembra che solo il gancio findOneAndUpdatesia lavoro

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

0

Utilizzare una funzione per restituire il valore predefinito calcolato:

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

non c'è bisogno di concludere Date.now()una funzione:...default: Date.now()
karlkurzer,

1
Lo avvolgo in una funzione in modo da poter deridere '.now ()' nei test. Altrimenti viene eseguito una sola volta durante l'inizializzazione e il valore non può essere facilmente modificato.
orourkedd,

1
Nota che default: Date.now()sarebbe sbagliato. Semmai lo è default: Date.now. Altrimenti tutti i tuoi documenti avranno lo stesso timestamp: l'ora in cui è stata avviata la domanda;)
Max Truxa

Mi piace la tua default: Date.nowstrategia. molto più pulito.
orourkedd,

0

In realtà lo faccio nella parte posteriore

Se tutto va bene con l'aggiornamento:

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

Utilizzare machinepack-datetime per formattare il 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
});

Il pacchetto macchina è fantastico con API chiare a differenza del mondo Javascript espresso o generale.


-2

È possibile utilizzare middleware e virtual . Ecco un esempio per il tuo updated_atcampo:

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

Quando verrebbe effettivamente impostato? e persisterà? Quindi tra 3 giorni, avrebbe ancora una data di 3 giorni fa?
chovy

il virtuale verrà chiamato ogni volta che cambi la proprietà data, in questo caso name. E sì, dovrebbe essere persistente.
zemirco,

funzionerebbe per tutti i campi sull'oggetto Item? I "m non sono sicuro questa soluzione fa quello che voglio
Chovy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.