Bella domanda, stavo esaminando anche questo.
Crea una nuova versione per ogni modifica
Mi sono imbattuto nel modulo di versioning del driver Mongoid per Ruby. Non l'ho usato da solo, ma da quello che ho trovato , aggiunge un numero di versione a ciascun documento. Le versioni precedenti sono incorporate nel documento stesso. Lo svantaggio principale è che l' intero documento viene duplicato su ogni modifica , il che comporta la memorizzazione di molti contenuti duplicati quando si ha a che fare con documenti di grandi dimensioni. Questo approccio va bene anche quando hai a che fare con documenti di piccole dimensioni e / o non aggiorni documenti molto spesso.
Memorizza solo le modifiche in una nuova versione
Un altro approccio sarebbe quello di memorizzare solo i campi modificati in una nuova versione . Quindi puoi 'appiattire' la tua storia per ricostruire qualsiasi versione del documento. Ciò è piuttosto complesso, poiché è necessario tenere traccia delle modifiche nel modello e archiviare gli aggiornamenti e le eliminazioni in modo tale che l'applicazione possa ricostruire il documento aggiornato. Questo potrebbe essere difficile, dato che hai a che fare con documenti strutturati piuttosto che con tabelle SQL piatte.
Memorizza le modifiche all'interno del documento
Ogni campo può anche avere una storia individuale. La ricostruzione di documenti per una data versione è molto più semplice in questo modo. Nell'applicazione non è necessario tenere traccia in modo esplicito delle modifiche, ma è sufficiente creare una nuova versione della proprietà quando si modifica il suo valore. Un documento potrebbe assomigliare a questo:
{
_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" }
]
}
]
}
Contrassegnare parte del documento come eliminato in una versione è comunque un po 'imbarazzante. È possibile introdurre un state
campo per le parti che possono essere eliminate / ripristinate dalla propria applicazione:
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
Con ciascuno di questi approcci è possibile archiviare una versione aggiornata e appiattita in una raccolta e i dati della cronologia in una raccolta separata. Ciò dovrebbe migliorare i tempi delle query se sei interessato solo all'ultima versione di un documento. Ma quando hai bisogno sia della versione più recente che dei dati storici, devi eseguire due query, anziché una. Pertanto, la scelta di utilizzare una raccolta singola rispetto a due raccolte separate dovrebbe dipendere dalla frequenza con cui l'applicazione richiede le versioni storiche .
Gran parte di questa risposta è solo una scarica di cervello dei miei pensieri, non ho ancora provato nulla di tutto questo. Ripensandoci, la prima opzione è probabilmente la soluzione più semplice e migliore, a meno che il sovraccarico di dati duplicati non sia molto significativo per la tua applicazione. La seconda opzione è piuttosto complessa e probabilmente non vale la pena. La terza opzione è fondamentalmente un'ottimizzazione dell'opzione due e dovrebbe essere più facile da implementare, ma probabilmente non vale lo sforzo di implementazione a meno che non si possa davvero andare con l'opzione uno.
In attesa di feedback su questo, e soluzioni di altre persone al problema :)