Fügen Sie den Mungo-Schemas die Felder created_at und updated_at hinzu


166

Gibt es eine Möglichkeit, einem Mungo-Schema die Felder "created_at" und "updated_at" hinzuzufügen, ohne sie bei jedem Aufruf von "MyModel ()" übergeben zu müssen?

Das Feld created_at ist ein Datum und wird nur hinzugefügt, wenn ein Dokument erstellt wird. Das Feld update_at wird jedes Mal mit einem neuen Datum aktualisiert, wenn save () für ein Dokument aufgerufen wird.

Ich habe dies in meinem Schema versucht, aber das Feld wird nur angezeigt, wenn ich es ausdrücklich hinzufüge:

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

Ich habe genau das getan, was du getan hast und es hat funktioniert. Verwenden von Mungo 4.8.4. Könnte eine neue Sache sein?
martinedwards

1
das war vor einiger Zeit.
Chovy

Ja, ich dachte, es wäre erwähnenswert, dass das oben genannte jetzt funktioniert.
Martinedwards

Antworten:


130

Ab Mongoose 4.0 können Sie jetzt eine Zeitstempeloption für das Schema festlegen, damit Mongoose dies für Sie erledigt:

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

Sie können den Namen der verwendeten Felder folgendermaßen ändern:

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

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


2
Einverstanden ist dies die beste Option in Mongoose 4.0.
Tadd Giles

258

UPDATE: (5 Jahre später)

Hinweis: Wenn Sie sich für die Verwendung von Kappa Architecture ( Event Sourcing + CQRS ) entscheiden, benötigen Sie überhaupt kein aktualisiertes Datum. Da es sich bei Ihren Daten um ein unveränderliches Ereignisprotokoll handelt, das nur angehängt werden kann, benötigen Sie immer nur das Erstellungsdatum des Ereignisses. Ähnlich der unten beschriebenen Lambda-Architektur . Ihr Anwendungsstatus ist dann eine Projektion des Ereignisprotokolls (abgeleitete Daten). Wenn Sie ein nachfolgendes Ereignis über eine vorhandene Entität erhalten, verwenden Sie das Erstellungsdatum dieses Ereignisses als Aktualisierungsdatum für Ihre Entität. Dies ist eine häufig verwendete (und häufig missverstandene) Praxis in Miceroservice-Systemen.

UPDATE: (4 Jahre später)

Wenn Sie ObjectIdals _idFeld verwenden (was normalerweise der Fall ist), müssen Sie nur Folgendes tun:

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

Überprüfen Sie meine ursprüngliche Antwort unten, wie Sie den erstellten Zeitstempel aus dem _idFeld erhalten. Wenn Sie IDs von einem externen System verwenden müssen, überprüfen Sie die Antwort von Roman Rhrn Nesterov.

UPDATE: (2,5 Jahre später)

Sie können jetzt die Option #timestamps mit der Mungo-Version> = 4.0 verwenden.

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

Wenn Sie Ihrem Schema Zeitstempel, Mungos createdAtund updatedAtFelder zuweisen, wird der Typ zugewiesen Date.

Sie können auch die Namen der Zeitstempeldateien angeben:

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

Hinweis: Wenn Sie an einer großen Anwendung mit kritischen Daten arbeiten, sollten Sie die Aktualisierung Ihrer Dokumente überdenken. Ich würde Ihnen raten, mit unveränderlichen Daten zu arbeiten, die nur Anhänge enthalten ( Lambda-Architektur ). Dies bedeutet, dass Sie immer nur Einsätze zulassen. Aktualisierungen und Löschungen sollten nicht erlaubt sein! Wenn Sie einen Datensatz "löschen" möchten, können Sie einfach eine neue Version des Dokuments mit einigen timestamp/ version abgelegt und dann ein deletedFeld auf setzen true. Wenn Sie ein Dokument aktualisieren möchten, erstellen Sie ein neues Dokument, wobei die entsprechenden Felder aktualisiert und die restlichen Felder kopiert werden. Um dieses Dokument abzufragen, erhalten Sie das Dokument mit dem neuesten Zeitstempel oder der höchsten Version nicht "gelöscht" (diedeleted Feld ist undefiniert oder falsch`).

Durch die Unveränderlichkeit der Daten wird sichergestellt, dass Ihre Daten debuggbar sind. Sie können den Verlauf jedes Dokuments verfolgen. Sie können auch ein Rollback auf die vorherige Version eines Dokuments durchführen, wenn ein Fehler auftritt. Wenn Sie sich für eine solche Architektur entscheiden, ObjectId.getTimestamp()ist dies alles, was Sie brauchen, und sie ist nicht mungoabhängig.


URSPRÜNGLICHE ANTWORT:

Wenn Sie ObjectId als Identitätsfeld verwenden, benötigen Sie kein created_atFeld. ObjectIds haben eine Methode namens getTimestamp().

ObjectId ("507c7f79bcf86cd7994f6c0e"). GetTimestamp ()

Dies gibt die folgende Ausgabe zurück:

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

Weitere Informationen hier Wie extrahiere ich das Erstellungsdatum aus einer Mongo ObjectID

Um Dateien hinzuzufügen updated_at, müssen Sie Folgendes verwenden:

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
Wie macht man das in Mongoose / node.js?
Zebra Propulsion Lab

6
Das ist wissenswert, auch wenn es nicht die Lösung ist, die verwendet wird, sehr interessant!
unwissentlich

Aber wenn ich das Erstellungsdatum an die Ansicht übergeben möchte, müsste ich dafür eine spezielle Variable festlegen oder die ID richtig übergeben?

3
Ich schätze die anfängliche Antwort, aber die Befürwortung der Verwendung der Lambda-Architektur klingt auch nach einer großartigen Möglichkeit, 5-fache Ebenen von Metaproblemen zu lösen und möglicherweise niemals die CRUD-App zu erstellen, anstatt sie zu erstellen und einfach zu halten, es sei denn, die Komplexität dieses Ansatzes ist wirklich gerechtfertigt. Denken Sie daran, dass Sie über MongoDB posten, das von Anfang an "kaum" skaliert, und Sie plädieren für einen neuen Rekord für jeden Schreibvorgang, der Mongo in jedem sinnvollen Maßstab schnell tötet. Verschieben Sie dies in den Abschnitt Cassandra ...
John Culviner

1
Ich habe mein Backend-Design geändert, um dank der in dieser Antwort enthaltenen Informationen weiche Löschvorgänge anstelle von echten Löschvorgängen durchzuführen. Es bietet ein tieferes Wissen, das wirklich nützlich ist.
Kenna

133

Das habe ich letztendlich getan:

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. Speichern Sie die aktuelle Uhrzeit in einer lokalen Variable und weisen Sie sie zu, anstatt jedes Mal new Date () aufzurufen. Dadurch wird sichergestellt, dass created_at und updated_at beim ersten Durchgang denselben excect-Wert haben. 2. neues Datum => neues Datum ()
Shay Erlichmen

13
Ich möchte nur darauf hinweisen, dass Sie, wenn Sie ObjectId verwenden, das created_at von dort abrufen können. Sie benötigen kein separates Feld. AuscheckengetTimestamp()
Xerri

6
Eine andere Option für das created_at könnte sein, das Modell in -> created_at: {Typ: Datum, Standard: Date.now},
OscarVGG

1
@ajbraus Machen Sie ein Schema-Plugin
wlingke

2
Verwenden Sie auch, Date.now()wo es möglich ist, anstatt es new Dateschneller zu machen, da es eine statische Methode ist
Karlkurzer

107

Verwenden Sie die integrierte timestampsOption für Ihr Schema.

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

Dies fügt automatisch createdAtund hinzuupdatedAt Felder zu Ihrem Schema.

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


1
Benötigt Mungo-Version> = 4.0
Jensen

2
Ich finde die Dokumente unklar - dies fügt die Felder hinzu, aber stellt es auch sicher, dass sie bei jedem Update aktualisiert werden?
Ludwik

Im Allgemeinen wird createdAt immer nur einmal gespeichert ... wenn ein Objekt erstellt wird. updatedAtwird bei jedem neuen Speichern aktualisiert (wenn das Objekt geändert wird)
codyc4321

1
Ich habe dieses "2016-12-07T11: 46: 46.066Z" erhalten. Könnte bitte das Zeitstempelformat erklären, wie sich die Zeitzone ändert? ist mongoDB Server Zeitzone nehmen?
Mahesh K

@mcompeau, danke für die Antwort! Ich weiß, dass es ein langer Weg ist, aber erinnern Sie sich zufällig, ob auf diese Weise erstellte Felder als Index verwendet werden können?
Manidos

29

Wenn verwenden update()oderfindOneAndUpdate()

mit {upsert: true} Option

Sie können verwenden $setOnInsert

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

1
Dies funktioniert in den meisten Mongo-Bibliotheken. Wechsel zu akzeptierter Antwort
chovy

1
Wenn Sie das Standardfeld von Mogo verwenden _id, benötigen Sie kein createdAtFeld. Überprüfen Sie meine Antwort unten für weitere Details.
Pavel Nikolov

1
... meine ORIGINAL ANTWORT überprüfen .
Pavel Nikolov

25

Fügen timestampsSie Schemadies dann hinzu createdAtund updatedAtgenerieren Sie es automatisch für Sie

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

Geben Sie hier die Bildbeschreibung ein
Sie können auch ändern , createdAt -> created_atindem

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

2
Jetzt, da Mongoose all diese Arbeit für Sie erledigt, stimme ich zu, dass dies jetzt die beste Lösung ist.
Vince Bowdren

Ja, stimme dem zu @VinceBowdren
Mr.spShuvo

8

So habe ich erreicht und aktualisiert.

In meinem Schema habe ich das erstellte und aktualisierte wie folgt hinzugefügt:

   / **
     * Artikelschema
     * /
    var ArticleSchema = neues Schema ({
        erstellt: {
            Typ: Datum,
            Standard: Date.now
        },
        Aktualisiert: {
            Typ: Datum,
            Standard: Date.now
        },
        Titel: {
            Typ: String,
            Standard: '',
            trimmen: wahr,
            Erforderlich: 'Titel darf nicht leer sein'
        },
        Inhalt: {
            Typ: String,
            Standard: '',
            trimmen: wahr
        },
        Benutzer: {
            Typ: Schema.ObjectId,
            ref: 'Benutzer'
        }}
    });

Dann habe ich in meiner Artikelaktualisierungsmethode im Artikel-Controller Folgendes hinzugefügt:

/ **
     * Aktualisieren Sie einen Artikel
     * /
    exports.update = Funktion (req, res) {
        var article = req.article;

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

        article.save (Funktion (err) {
            if (err) {
                return res.status (400) .send ({
                    Nachricht: errorHandler.getErrorMessage (err)
                });
            } else {
                res.json (Artikel);
            }}
        });
    };

Die fett gedruckten Abschnitte sind die Teile von Interesse.



4

Sie können das timestampPlugin von verwenden mongoose-troop, um dieses Verhalten einem beliebigen Schema hinzuzufügen.


3

Sie können dieses Plugin sehr einfach verwenden. Aus den Dokumenten:

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

Und legen Sie auch den Namen der Felder fest, wenn Sie möchten:

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

2

Wir können dies erreichen, indem wir auch das Schema-Plugin verwenden .

In helpers/schemaPlugin.jsDatei

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

und in models/ItemSchema.jsDatei:

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

In Ihrem Modellschema, fügen Sie einfach eine Attribut Zeitstempel und assign Wert wahr , um es wie folgt: -

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

Was wird das tun?
Chovy

Das Zeitstempelattribut fügt in jedem Dokument die Felder created_at und updated_at hinzu. Das Feld "Created_at" gibt den Zeitpunkt der Erstellung des Dokuments an, und das Feld "update_at" gibt den Zeitpunkt der Aktualisierung an, falls sonst die Erstellungszeit des Dokuments. Der Wert beider Felder liegt im ISO-Zeitformat vor. Hoffe das klärt deine Zweifel 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 }
});

Jetzt können Sie dies verwenden, sodass diese Option nicht in jede Tabelle aufgenommen werden muss


1

Meine Mungo-Version ist 4.10.2

Scheint nur der Haken findOneAndUpdateist Arbeit

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

0

Verwenden Sie eine Funktion, um den berechneten Standardwert zurückzugeben:

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

Keine Notwendigkeit, Date.now()eine Funktion ...default: Date.now()
einzuwickeln,

1
Ich verpacke es in eine Funktion, damit ich '.now ()' in Tests verspotten kann. Andernfalls wird es während der Initialisierung nur einmal ausgeführt und der Wert kann nicht einfach geändert werden.
orourkedd

1
Beachten Sie, dass default: Date.now()das falsch wäre. Wenn überhaupt, ist es default: Date.now. Andernfalls haben alle Ihre Dokumente den gleichen Zeitstempel: Die Zeit, zu der Ihre Anwendung gestartet wurde;)
Max Truxa

Ich mag deine default: Date.nowStrategie. viel sauberer.
orourkedd

0

Ich mache das eigentlich hinten

Wenn mit der Aktualisierung alles gut geht:

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

Verwenden Sie machinepack-datetime, um die datetime zu formatieren.

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

Im Gegensatz zur Express- oder allgemeinen Javascript-Welt ist das Maschinenpaket mit einer klaren API großartig.


-2

Sie können Middleware und Virtuals verwenden . Hier ist ein Beispiel für Ihr updated_atFachgebiet:

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

Wann würde dies tatsächlich eingestellt werden? und wird es bestehen bleiben? Also in 3 Tagen hätte es noch ein Datum von vor 3 Tagen?
Chovy

In diesem Fall wird die virtuelle Datei aufgerufen, wenn Sie die angegebene Eigenschaft ändern name. Und ja, es sollte hartnäckig sein.
Zemirco

Würde dies für alle Felder im Objekt Item funktionieren? Ich bin mir nicht sicher, ob diese Lösung das tut, was ich will
chovy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.