Möglichkeiten zur Implementierung der Datenversionierung in MongoDB

298

Können Sie uns Ihre Gedanken mitteilen, wie Sie die Datenversionierung in MongoDB implementieren würden? (Ich habe eine ähnliche Frage zu Cassandra gestellt . Wenn Sie irgendwelche Gedanken haben, welche Datenbank dafür besser ist, teilen Sie sie bitte mit.)

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

  • wird selten verwendet
  • wird auf einmal verwendet, um es in einer "Zeitmaschinen" -Mode zu präsentieren
  • Es wird nicht mehr als ein paar hundert Versionen für einen einzelnen Datensatz geben. Die Geschichte läuft nicht ab.

Ich denke über folgende Ansätze nach:

  • Erstellen Sie eine neue Objektsammlung, um den Verlauf von Datensätzen 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 Adressbuchdatensatzes' 
     'old_record': {'first_name': 'Jon', 'last_name': 'Doe' ...}
    }}
    

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

  • Speichern Sie Versionen als serialisiertes (JSON) Objekt, das an Adressbucheinträge angehängt ist. Ich bin nicht sicher, wie ich solche Objekte an MongoDB-Dokumente anhängen soll. Vielleicht als eine Reihe von Zeichenfolgen. ( Modelliert nach der einfachen Dokumentversionierung mit CouchDB )

Piotr Czapla
quelle
1
Ich möchte wissen, ob sich dies geändert hat, seit die Frage beantwortet wurde. Ich weiß nicht viel über Oplog, aber gab es das damals, würde es einen Unterschied machen?
Randy L
Mein Ansatz ist es, alle Daten als Zeitreihen zu betrachten.

Antworten:

152

Die erste große Frage beim Tauchen in dafür ist „wie wollen Sie speichern Changesets “ ?

  1. Diffs?
  2. Ganze Plattenkopien?

Mein persönlicher Ansatz wäre es, Unterschiede zu speichern. Da die Anzeige dieser Unterschiede wirklich eine besondere Aktion ist, würde ich die Unterschiede in eine andere "Geschichts" -Sammlung einfügen.

Ich würde die andere Sammlung verwenden, um Speicherplatz zu sparen. Sie möchten im Allgemeinen keinen vollständigen Verlauf für eine einfache Abfrage. Wenn Sie also den Verlauf aus dem Objekt heraushalten, können Sie ihn auch aus dem Speicher heraushalten, auf den häufig zugegriffen wird, wenn diese Daten abgefragt werden.

Um mir das Leben zu erleichtern, würde ich ein Verlaufsdokument erstellen, das ein Wörterbuch mit zeitgestempelten Unterschieden enthält. Etwas wie das:

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

Um mir das Leben wirklich zu erleichtern, 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 Form des Verlaufs, 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 den Umgang mit JSON-Unterschieden . Dies scheint eine robustere Methode zum Speichern der Unterschiede zu sein.

Gates VP
quelle
2
Würden Sie sich keine Sorgen machen, dass ein solches Verlaufsdokument (das Änderungsobjekt) mit der Zeit wächst und Aktualisierungen ineffizient werden? Oder wächst MongoDB problemlos mit Dokumenten?
Piotr Czapla
5
Schauen Sie sich die Bearbeitung an. Das Hinzufügen zu changesist wirklich einfach: db.hist.update({_id: ID}, {$set { changes.12345 : CHANGES } }, true)Dadurch wird ein Upsert ausgeführt, bei dem nur die erforderlichen Daten geändert werden. Mongo erstellt Dokumente mit "Pufferplatz", um diese Art von Änderung zu handhaben. Außerdem wird überwacht, wie sich Dokumente in einer Sammlung ändern, und die Puffergröße für jede Sammlung wird geändert. MongoDB ist also genau für diese Art von Änderung ausgelegt (neue Eigenschaft hinzufügen / zum Array verschieben).
Gates VP
2
Ich habe einige Tests durchgeführt und tatsächlich funktioniert die Platzreservierung ziemlich gut. Ich konnte den Leistungsverlust nicht feststellen, als die Datensätze am Ende der Datendatei neu zugewiesen wurden.
Piotr Czapla
4
Sie können github.com/mirek/node-rus-diff verwenden , um (MongoDB-kompatible) Differenzen für Ihren Verlauf zu generieren.
Mirek Rusin
1
Der JSON Patch RFC bietet eine Möglichkeit, Unterschiede auszudrücken. Es hat Implementierungen in mehreren Sprachen .
Jérôme
31

Es gibt ein Versionsschema namens "Vermongo", das einige Aspekte behandelt, die in den anderen Antworten nicht behandelt wurden.

Eines dieser Probleme sind gleichzeitige Aktualisierungen, ein anderes das Löschen von Dokumenten.

Vermongo speichert vollständige Dokumentkopien in einer Schattensammlung. In einigen Anwendungsfällen kann dies zu viel Overhead verursachen, aber ich denke, es vereinfacht auch viele Dinge.

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

Marian
quelle
5
Wie benutzt man es eigentlich?
hadees
6
Es gibt keine Dokumentation darüber, wie dieses Projekt tatsächlich verwendet wird. Ist es etwas, das irgendwie mit Mongo zusammenlebt? Es ist eine Java-Bibliothek? Ist es nur eine Art, über das Problem nachzudenken? Keine Idee und keine Hinweise werden gegeben.
ftrotter
1
Dies ist eigentlich eine Java-App und der relavante Code lebt hier: github.com/thiloplanz/v7files/blob/master/src/main/java/v7db/…
ftrotter
20

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

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

dataenthält alle Versionen. Das dataArray ist bestellt , neue Versionen werden nur $pushbis zum Ende des Arrays bearbeitet. data.vidist die Versions-ID, bei der es sich um eine inkrementelle Zahl handelt.

Holen Sie sich die neueste Version:

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

Holen Sie sich eine bestimmte Version von vid:

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

Geben Sie nur die angegebenen Felder zurück:

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

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

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

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

Die $andBedingung wird sicherstellen, dass dies 2die neueste ist vid.

Auf diese Weise ist kein eindeutiger Index erforderlich, aber die Anwendungslogik muss dafür sorgen, dass die vidEinfügung erhöht wird .

Entfernen Sie eine bestimmte Version:

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

Das ist es!

(Beachten Sie das Limit von 16 MB pro Dokument.)

Benjamin M.
quelle
Beim mmapv1-Speicher besteht jedes Mal, wenn eine neue Version zu Daten hinzugefügt wird, die Möglichkeit, dass das Dokument verschoben wird.
raok1997
Ja, das ist richtig. Wenn Sie jedoch nur gelegentlich neue Versionen hinzufügen, sollte dies vernachlässigbar sein.
Benjamin M
9

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

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

Ich erkläre das Modell hier weiter: http://software.danielwatrous.com/representing-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/

Einschließlich des gesamten Codes, den Sie bei Bedarf teilen können

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

Daniel Watrous
quelle
Super Zeug :)
Jonathan
4

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

Mungo-Patch-Geschichte

bmw15
quelle
4

Eine andere Möglichkeit ist die Verwendung des Mungo-Verlaufs- Plugins.

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.
Muhammad Reda
quelle
1

Ich habe das folgende Paket für ein Meteor / MongoDB-Projekt verwendet und es funktioniert gut. Der Hauptvorteil besteht darin, dass der Verlauf / die Revisionen in einem Array im selben Dokument gespeichert werden, sodass keine zusätzlichen Veröffentlichungen oder Middleware für den Zugriff auf den Änderungsverlauf erforderlich sind . Es kann eine begrenzte Anzahl früherer Versionen unterstützen (z. B. die letzten zehn Versionen), es unterstützt auch die Verkettung von Änderungen (sodass alle Änderungen, die innerhalb eines bestimmten Zeitraums vorgenommen wurden, von einer Revision abgedeckt werden).

Nicklozon / Meteor-Sammlung-Revisionen

Eine weitere Soundoption ist die Verwendung von Meteor Vermongo ( hier ).

Helcode
quelle