Möglichkeiten zur Implementierung der Datenversionierung in MongoDB

Können Sie Ihre Gedanken teilen, wie Sie die Datenversionierung in MongoDB implementieren würden? (Ich habe ähnliche Fragen bezüglich Cassandra gestellt . Wenn Sie irgendwelche Gedanken haben, welche DB besser ist, teilen Sie das bitte mit)

Angenommen, ich muss Datensätze in einem einfachen Adressbuch versionieren. (Adressbucheinträge werden als flache JSON-Objekte gespeichert). Ich erwarte, dass die Geschichte:

  • wird selten verwendet werden
  • wird auf einmal verwendet, um es in einer “Zeitmaschine” zu präsentieren
  • Es wird nicht mehr Versionen als ein paar hundert zu einem einzigen Datensatz geben. Geschichte wird nicht ablaufen.

Ich überlege mir folgende Ansätze:

  • Erstellen Sie eine neue Objektsammlung, um den Verlauf der Datensätze oder Änderungen an den Datensätzen zu speichern. Es würde ein Objekt pro Version mit einem Verweis auf den Adressbucheintrag speichern. Solche Aufzeichnungen würden wie folgt aussehen:

     {
      '_id': 'neue ID',
      'Benutzer': Benutzer-ID,
      'Zeitstempel': Zeitstempel,
      'address_book_id': 'ID des Adressbucheintrags' 
      'old_record': {'first_name': 'Jon', 'letzter_name': 'Doe' ...}
     }
    

    Dieser Ansatz kann geändert werden, um ein Array von Versionen pro Dokument zu speichern. Dies scheint jedoch eine langsamere Annäherung ohne irgendwelche Vorteile zu sein.

  • Speichern Sie Versionen als serialisiertes (JSON) Objekt, das an Adressbucheinträge angehängt ist. Ich bin mir nicht sicher, wie solche Objekte an MongoDB-Dokumente angehängt werden. Vielleicht als ein Array von Streichern. ( Nach Simple Document Versioning mit CouchDB modelliert )

Die erste große Frage beim Eintauchen lautet: “Wie möchten Sie Changesets speichern?”

  1. Diffs?
  2. Ganze Plattenkopien?

Mein persönlicher Ansatz wäre, Diffs zu speichern. Da die Anzeige dieser Diffs wirklich eine spezielle Aktion ist, würde ich die Diffs in eine andere “History” -Sammlung stellen.

Ich würde die andere Sammlung verwenden, um Speicherplatz zu sparen. Im Allgemeinen möchten Sie keine vollständige Historie für eine einfache Abfrage. Indem Sie also die Historie aus dem Objekt heraushalten, können Sie sie auch aus dem Speicher des häufig verwendeten Speichers heraushalten, wenn diese Daten abgefragt werden.

Um mir das Leben leichter zu machen, würde ich ein Geschichtsdokument machen, das ein Wörterbuch von zeitgestempelten Diffs enthält. Etwas wie das:

{ _id : "id of address book record", changes : { 1234567 : { "city" : "Omaha", "state" : "Nebraska" }, 1234568 : { "city" : "Kansas City", "state" : "Missouri" } } } 

Um mein Leben wirklich einfach zu machen, würde ich diesen Teil meiner DataObjects (EntityWrapper, was auch immer) für den Zugriff auf meine Daten verwenden. Im Allgemeinen haben diese Objekte eine Art von Verlauf, sodass Sie die save() -Methode leicht überschreiben können, um diese Änderung gleichzeitig vorzunehmen.

UPDATE: 2015-10

Es sieht so aus, als gäbe es jetzt eine Spezifikation für die Behandlung von JSON-Diffs . Dies scheint eine robustere Möglichkeit zu sein, die Diffs / Änderungen zu speichern.

Es gibt ein Versionierungsschema namens “Vermongo”, das einige Aspekte behandelt, die in den anderen Antworten nicht behandelt wurden.

Eines dieser Probleme ist die gleichzeitige Aktualisierung, ein anderes ist das Löschen von Dokumenten.

Vermongo speichert komplette Dokumentkopien in einer Schattensammlung. Für einige Anwendungsfälle kann dies zu viel Overhead verursachen, aber ich denke, es vereinfacht auch viele Dinge.

https://github.com/thiloplanz/v7files/wiki/Vermongo

Hier ist eine andere Lösung, die ein einziges Dokument für die aktuelle Version und alle alten Versionen verwendet:

 { _id: ObjectId("..."), data: [ { vid: 1, content: "foo" }, { vid: 2, content: "bar" } ] } 

data enthalten alle Versionen. Das Datenarray ist geordnet , neue Versionen erhalten nur $push ed am Ende des Arrays. data.vid ist die Versions-ID, die eine data.vid Nummer ist.

Hol dir die neueste Version:

 find( { "_id":ObjectId("...") }, { "data":{ $slice:-1 } } ) 

Erhalte eine bestimmte Version von vid :

 find( { "_id":ObjectId("...") }, { "data":{ $elemMatch:{ "vid":1 } } } ) 

Nur angegebene Felder zurückgeben:

 find( { "_id":ObjectId("...") }, { "data":{ $elemMatch:{ "vid":1 } }, "data.content":1 } ) 

Neue Version einfügen : (und gleichzeitiges Einfügen / Update verhindern)

 update( { "_id":ObjectId("..."), $and:[ { "data.vid":{ $not:{ $gt:2 } } }, { "data.vid":2 } ] }, { $push:{ "data":{ "vid":3, "content":"baz" } } } ) 

2 ist die vid der aktuellsten Version und 3 wird die neue Version eingefügt. Da Sie die vid der neuesten Version benötigen, ist es einfach, die vid der nächsten Version nextVID = oldVID + 1 : nextVID = oldVID + 1 .

Die $and Bedingung stellen sicher, dass 2 das neueste vid .

Auf diese Weise ist kein eindeutiger Index erforderlich, aber die Anwendungslogik muss dafür sorgen, dass die vid beim Einfügen erhöht wird.

Entfernen Sie eine bestimmte Version:

 update( { "_id":ObjectId("...") }, { $pull:{ "data":{ "vid":2 } } } ) 

Das ist es!

(Erinnere dich an das Limit von 16 MB pro Dokument)

Wenn Sie eine fertige Lösung suchen –

Mongoid hat eine einfache Versionierung eingebaut

http://mongoid.org/en/mongoid/docs/extras.html#versioning

mongoid-history ist ein Ruby-Plugin, das mit Auditing, Undo und Redo eine wesentlich kompliziertere Lösung bietet

https://github.com/aq1018/mongoid-history

Ich habe diese Lösung durchgearbeitet, die eine veröffentlichte, Entwurfs- und historische Version der Daten enthält:

 { published: {}, draft: {}, history: { "1" : { metadata: , document: {} }, ... } } 

Ich erkläre das Modell hier weiter: http://software.danielwatrous.com/representting-revision-data-in-mongodb/

Für diejenigen, die so etwas in Java implementieren können, hier ein Beispiel:

http://software.danielwatrous.com/using-java-to-work-with-versioned-data/

Wenn Sie möchten, können Sie den gesamten Code, den Sie abzweigen können, einbinden

https://github.com/dwatrous/mongodb-revision-objects

Wenn Sie Mungo verwenden, habe ich festgestellt, dass das folgende Plugin eine nützliche Implementierung des JSON-Patch- Formats ist

Mungo-Patch-Geschichte

Eine andere Möglichkeit ist das Mongoose-History Plugin.

 let mongoose = require('mongoose'); let mongooseHistory = require('mongoose-history'); let Schema = mongoose.Schema; let MySchema = Post = new Schema({ title: String, status: Boolean }); MySchema.plugin(mongooseHistory); // The plugin will automatically create a new collection with the schema name + "_history". // In this case, collection with name "my_schema_history" will be created. 

Ich habe das folgende Paket für ein Meteor / MongoDB-Projekt verwendet, und es funktioniert gut, der Hauptvorteil ist, dass es Geschichte / Revisionen in einem Array in demselben Dokument speichert, daher keine zusätzliche Publikationen oder Middleware für den Änderungsverlauf benötigt . Es kann eine begrenzte Anzahl von früheren Versionen (z. B. die letzten zehn Versionen) unterstützen, es unterstützt auch die Änderung der Verkettung (alle Änderungen innerhalb eines bestimmten Zeitraums werden von einer Revision abgedeckt).

Nicklozon / Meteor-Sammlung-Revisionen

Eine weitere Soundoption ist Meteor Vermongo ( hier )

Versuchen Sie es mit Javers. Gute Bibliothek.