MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB/NoSQL:Aufbewahrung des Dokumentänderungsverlaufs

Gute Frage, ich habe mich auch damit beschäftigt.

Bei jeder Änderung eine neue Version erstellen

Ich bin auf das Versioning-Modul des Mongoid-Treibers für Ruby gestoßen. Ich habe es selbst nicht verwendet, aber nach dem, was ich finden konnte, fügt es jedem Dokument eine Versionsnummer hinzu. Ältere Versionen sind im Dokument selbst eingebettet. Der größte Nachteil ist, dass das gesamte Dokument bei jeder Änderung dupliziert wird , was dazu führt, dass viele doppelte Inhalte gespeichert werden, wenn Sie mit großen Dokumenten arbeiten. Dieser Ansatz ist jedoch in Ordnung, wenn Sie mit kleinen Dokumenten zu tun haben und/oder Dokumente nicht sehr oft aktualisieren.

Änderungen nur in einer neuen Version speichern

Ein anderer Ansatz wäre, nur die geänderten Felder in einer neuen Version zu speichern . Dann können Sie Ihre Historie „glätten“, um eine beliebige Version des Dokuments zu rekonstruieren. Dies ist jedoch ziemlich komplex, da Sie Änderungen in Ihrem Modell nachverfolgen und Aktualisierungen und Löschungen so speichern müssen, dass Ihre Anwendung das aktuelle Dokument rekonstruieren kann. Dies könnte schwierig sein, da Sie es mit strukturierten Dokumenten und nicht mit flachen SQL-Tabellen zu tun haben.

Änderungen im Dokument speichern

Jedes Feld kann auch eine individuelle Historie haben. Das Rekonstruieren von Dokumenten zu einer bestimmten Version ist auf diese Weise viel einfacher. In Ihrer Anwendung müssen Sie Änderungen nicht explizit nachverfolgen, sondern erstellen einfach eine neue Version der Eigenschaft, wenn Sie ihren Wert ändern. Ein Dokument könnte etwa so aussehen:

{
  _id: "4c6b9456f61f000000007ba6"
  title: [
    { version: 1, value: "Hello world" },
    { version: 6, value: "Foo" }
  ],
  body: [
    { version: 1, value: "Is this thing on?" },
    { version: 2, value: "What should I write?" },
    { version: 6, value: "This is the new body" }
  ],
  tags: [
    { version: 1, value: [ "test", "trivial" ] },
    { version: 6, value: [ "foo", "test" ] }
  ],
  comments: [
    {
      author: "joe", // Unversioned field
      body: [
        { version: 3, value: "Something cool" }
      ]
    },
    {
      author: "xxx",
      body: [
        { version: 4, value: "Spam" },
        { version: 5, deleted: true }
      ]
    },
    {
      author: "jim",
      body: [
        { version: 7, value: "Not bad" },
        { version: 8, value: "Not bad at all" }
      ]
    }
  ]
}

Das Markieren eines Teils des Dokuments als gelöscht in einer Version ist jedoch immer noch etwas umständlich. Sie könnten einen state einführen Feld für Teile, die aus Ihrer Anwendung gelöscht/wiederhergestellt werden können:

{
  author: "xxx",
  body: [
    { version: 4, value: "Spam" }
  ],
  state: [
    { version: 4, deleted: false },
    { version: 5, deleted: true }
  ]
}

Mit jedem dieser Ansätze können Sie eine aktuelle und vereinfachte Version in einer Sammlung und die Verlaufsdaten in einer separaten Sammlung speichern. Dies sollte die Abfragezeiten verbessern, wenn Sie nur an der neuesten Version eines Dokuments interessiert sind. Wenn Sie jedoch sowohl die neueste Version als auch historische Daten benötigen, müssen Sie statt einer zwei Abfragen durchführen. Die Wahl zwischen einer einzelnen Sammlung und zwei separaten Sammlungen sollte also davon abhängen, wie oft Ihre Anwendung die historischen Versionen benötigt .

Der größte Teil dieser Antwort ist nur ein Brain Dump meiner Gedanken, ich habe noch nichts davon ausprobiert. Rückblickend ist die erste Option wahrscheinlich die einfachste und beste Lösung, es sei denn, der Aufwand durch doppelte Daten ist für Ihre Anwendung sehr erheblich. Die zweite Option ist ziemlich komplex und wahrscheinlich den Aufwand nicht wert. Die dritte Option ist im Grunde eine Optimierung von Option zwei und sollte einfacher zu implementieren sein, ist aber wahrscheinlich den Implementierungsaufwand nicht wert, es sei denn, Sie können sich wirklich nicht für Option eins entscheiden.

Ich freue mich auf Feedback dazu und auf Lösungen anderer Leute für das Problem :)