Bra fråga, jag tittade på det här själv också.
Skapa en ny version vid varje ändring
Jag stötte på versionsmodulen för Mongoid-drivrutinen för Ruby. Jag har inte använt det själv, men vad jag kunde hitta lägger det till ett versionsnummer till varje dokument. Äldre versioner är inbäddade i själva dokumentet. Den stora nackdelen är att hela dokumentet dupliceras vid varje ändring , vilket kommer att resultera i att mycket duplicerat innehåll lagras när du har att göra med stora dokument. Detta tillvägagångssätt är dock bra när du har att göra med små dokument och/eller inte uppdaterar dokument särskilt ofta.
Lagra bara ändringar i en ny version
Ett annat tillvägagångssätt skulle vara att lagra endast de ändrade fälten i en ny version . Sedan kan du "platta till" din historik för att rekonstruera valfri version av dokumentet. Detta är dock ganska komplicerat, eftersom du behöver spåra ändringar i din modell och lagra uppdateringar och raderingar på ett sätt så att din applikation kan rekonstruera det uppdaterade dokumentet. Detta kan vara knepigt eftersom du har att göra med strukturerade dokument snarare än platta SQL-tabeller.
Lagra ändringar i dokumentet
Varje fält kan också ha en individuell historik. Att rekonstruera dokument till en given version är mycket lättare på detta sätt. I din applikation behöver du inte explicit spåra ändringar, utan bara skapa en ny version av egenskapen när du ändrar dess värde. Ett dokument kan se ut ungefär så här:
{
_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" }
]
}
]
}
Att markera en del av dokumentet som borttaget i en version är dock fortfarande något besvärligt. Du kan införa ett state
fält för delar som kan raderas/återställas från din applikation:
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
Med var och en av dessa metoder kan du lagra en uppdaterad och tillplattad version i en samling och historikdata i en separat samling. Detta bör förbättra frågetiderna om du bara är intresserad av den senaste versionen av ett dokument. Men när du behöver både den senaste versionen och historiska data, måste du utföra två frågor istället för en. Så valet att använda en enda samling kontra två separata samlingar bör bero på hur ofta din applikation behöver de historiska versionerna .
Det mesta av det här svaret är bara en hjärndump av mina tankar, jag har faktiskt inte provat något av det här än. När man ser tillbaka på det är det första alternativet förmodligen den enklaste och bästa lösningen, såvida inte omkostnadsbeloppet för dubbletter av data är mycket viktigt för din applikation. Det andra alternativet är ganska komplicerat och är förmodligen inte värt ansträngningen. Det tredje alternativet är i grunden en optimering av alternativ två och borde vara enklare att implementera, men är förmodligen inte värt implementeringsansträngningen om du inte verkligen kan gå med alternativ ett.
Ser fram emot feedback på detta och andras lösningar på problemet :)