Goede vraag, ik was hier zelf ook naar aan het kijken.
Maak bij elke wijziging een nieuwe versie
Ik kwam de Versioning-module van de Mongoid-driver voor Ruby tegen. Ik heb het zelf niet gebruikt, maar van wat ik kon vinden, voegt het een versienummer toe aan elk document. Oudere versies zijn ingesloten in het document zelf. Het grote nadeel is dat het hele document bij elke wijziging wordt gedupliceerd , wat ertoe leidt dat er veel dubbele inhoud wordt opgeslagen wanneer u met grote documenten werkt. Deze aanpak is echter prima als je te maken hebt met kleine documenten en/of niet vaak documenten bijwerkt.
Sla alleen wijzigingen op in een nieuwe versie
Een andere benadering zou zijn om alleen de gewijzigde velden op te slaan in een nieuwe versie . Vervolgens kunt u uw geschiedenis 'afvlakken' om elke versie van het document te reconstrueren. Dit is echter nogal complex, omdat u wijzigingen in uw model moet bijhouden en updates en verwijderingen moet opslaan op een manier dat uw toepassing het up-to-date document kan reconstrueren. Dit kan lastig zijn, omdat je te maken hebt met gestructureerde documenten in plaats van met platte SQL-tabellen.
Wijzigingen opslaan in het document
Elk veld kan ook een individuele geschiedenis hebben. Het reconstrueren van documenten naar een bepaalde versie is op deze manier veel gemakkelijker. In uw toepassing hoeft u wijzigingen niet expliciet bij te houden, maar maakt u gewoon een nieuwe versie van de eigenschap wanneer u de waarde ervan wijzigt. Een document kan er ongeveer zo uitzien:
{
_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" }
]
}
]
}
Het markeren van een deel van het document als verwijderd in een versie is echter nog steeds enigszins onhandig. Je zou een state
kunnen introduceren veld voor onderdelen die kunnen worden verwijderd/hersteld vanuit uw applicatie:
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
Met elk van deze benaderingen kun je een up-to-date en afgeplatte versie opslaan in één collectie en de historiegegevens in een aparte collectie. Dit zou de querytijden moeten verbeteren als u alleen geïnteresseerd bent in de nieuwste versie van een document. Maar als u zowel de nieuwste versie als historische gegevens nodig heeft, moet u twee query's uitvoeren in plaats van één. Dus de keuze voor het gebruik van één verzameling versus twee afzonderlijke verzamelingen moet afhangen van hoe vaak uw toepassing de historische versies nodig heeft .
Het grootste deel van dit antwoord is slechts een hersenkraker van mijn gedachten, ik heb dit nog niet echt geprobeerd. Als we erop terugkijken, is de eerste optie waarschijnlijk de gemakkelijkste en beste oplossing, tenzij de overhead van dubbele gegevens erg belangrijk is voor uw toepassing. De tweede optie is vrij complex en waarschijnlijk niet de moeite waard. De derde optie is in feite een optimalisatie van optie twee en zou gemakkelijker te implementeren moeten zijn, maar is waarschijnlijk de implementatie-inspanning niet waard, tenzij je echt niet voor optie één kunt gaan.
Ik kijk uit naar feedback hierover en de oplossingen van andere mensen voor het probleem :)