Dobre pytanie, sam też się tym przyjrzałem.
Utwórz nową wersję przy każdej zmianie
Natknąłem się na moduł wersjonowania sterownika Mongoid dla Rubiego. Sam go nie używałem, ale z tego, co udało mi się znaleźć , dodaje numer wersji do każdego dokumentu. Starsze wersje są osadzone w samym dokumencie. Główną wadą jest to, że cały dokument jest duplikowany przy każdej zmianie , co spowoduje przechowywanie wielu zduplikowanych treści, gdy masz do czynienia z dużymi dokumentami. Takie podejście jest dobre, gdy masz do czynienia z dokumentami o małych rozmiarach i / lub nie aktualizujesz dokumentów zbyt często.
Przechowuj zmiany tylko w nowej wersji
Innym podejściem byłoby przechowywanie tylko zmienionych pól w nowej wersji . Następnie możesz „spłaszczyć” swoją historię, aby zrekonstruować dowolną wersję dokumentu. Jest to jednak dość złożone, ponieważ musisz śledzić zmiany w modelu oraz przechowywać aktualizacje i usuwać w taki sposób, aby aplikacja mogła zrekonstruować aktualny dokument. Może to być trudne, ponieważ masz do czynienia z dokumentami strukturalnymi zamiast płaskich tabel SQL.
Przechowuj zmiany w dokumencie
Każde pole może mieć również indywidualną historię. W ten sposób odtworzenie dokumentów do danej wersji jest znacznie łatwiejsze. W swojej aplikacji nie musisz jawnie śledzić zmian, po prostu utwórz nową wersję właściwości, gdy zmienisz jej wartość. Dokument mógłby wyglądać mniej więcej tak:
{
_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",
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" }
]
}
]
}
Oznaczanie części dokumentu jako usuniętej w wersji jest jednak nadal nieco niewygodne. Możesz wprowadzić state
pole dla części, które można usunąć / przywrócić z aplikacji:
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
Przy każdym z tych podejść można przechowywać aktualną i spłaszczoną wersję w jednej kolekcji, a dane historyczne w osobnej kolekcji. Powinno to skrócić czas wykonywania zapytań, jeśli interesuje Cię tylko najnowsza wersja dokumentu. Ale gdy potrzebujesz zarówno najnowszej wersji, jak i danych historycznych, musisz wykonać dwa zapytania zamiast jednego. Zatem wybór użycia jednej kolekcji lub dwóch oddzielnych kolekcji powinien zależeć od tego, jak często aplikacja potrzebuje wersji historycznych .
Większość z tych odpowiedzi to tylko zrzut mózgu z moich myśli, właściwie jeszcze tego nie próbowałem. Patrząc wstecz, pierwsza opcja jest prawdopodobnie najłatwiejszym i najlepszym rozwiązaniem, chyba że obciążenie związane z duplikowaniem danych jest bardzo istotne dla aplikacji. Druga opcja jest dość złożona i prawdopodobnie nie jest warta wysiłku. Trzecia opcja jest w zasadzie optymalizacją opcji drugiej i powinna być łatwiejsza do wdrożenia, ale prawdopodobnie nie jest warta wysiłku wdrożeniowego, chyba że naprawdę nie możesz skorzystać z opcji pierwszej.
Czekam na opinie na ten temat i rozwiązania problemu przez innych :)