Bonne question, je me suis aussi penché sur cette question.
Créer une nouvelle version à chaque changement
Je suis tombé sur le module de gestion des versions du pilote Mongoid pour Ruby. Je ne l'ai pas utilisé moi-même, mais d'après ce que j'ai pu trouver , il ajoute un numéro de version à chaque document. Les versions plus anciennes sont intégrées dans le document lui-même. L'inconvénient majeur est que le document entier est dupliqué à chaque modification , ce qui entraînera le stockage d'un grand nombre de contenu dupliqué lorsque vous traitez de gros documents. Cette approche convient cependant lorsque vous traitez avec des documents de petite taille et / ou que vous ne mettez pas à jour des documents très souvent.
Stocker uniquement les modifications dans une nouvelle version
Une autre approche consisterait à stocker uniquement les champs modifiés dans une nouvelle version . Ensuite, vous pouvez «aplatir» votre historique pour reconstruire n'importe quelle version du document. Ceci est cependant assez complexe, car vous devez suivre les modifications de votre modèle et stocker les mises à jour et les suppressions de manière à ce que votre application puisse reconstruire le document à jour. Cela peut être délicat, car vous avez affaire à des documents structurés plutôt qu'à des tables SQL plates.
Stocker les modifications dans le document
Chaque champ peut également avoir une histoire individuelle. Reconstruire des documents dans une version donnée est beaucoup plus facile de cette façon. Dans votre application, vous n'avez pas à suivre explicitement les modifications, mais créez simplement une nouvelle version de la propriété lorsque vous modifiez sa valeur. Un document pourrait ressembler à ceci:
{
_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" }
]
}
]
}
Marquer une partie du document comme supprimée dans une version est cependant un peu gênant. Vous pouvez introduire un state
champ pour les pièces qui peuvent être supprimées / restaurées à partir de votre application:
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
Avec chacune de ces approches, vous pouvez stocker une version à jour et aplatie dans une collection et les données d'historique dans une collection distincte. Cela devrait améliorer les temps de requête si vous n'êtes intéressé que par la dernière version d'un document. Mais lorsque vous avez besoin à la fois de la dernière version et des données historiques, vous devrez effectuer deux requêtes au lieu d'une. Ainsi, le choix d'utiliser une seule collection plutôt que deux collections distinctes devrait dépendre de la fréquence à laquelle votre application a besoin des versions historiques .
La plupart de cette réponse n'est qu'une décharge cérébrale de mes pensées, je n'ai encore rien essayé de cela. En y repensant, la première option est probablement la solution la plus simple et la meilleure, à moins que la surcharge des données en double ne soit très importante pour votre application. La deuxième option est assez complexe et ne vaut probablement pas la peine. La troisième option est essentiellement une optimisation de l'option deux et devrait être plus facile à implémenter, mais ne vaut probablement pas l'effort d'implémentation à moins que vous ne puissiez vraiment pas opter pour l'option un.
Dans l'attente des commentaires à ce sujet et des solutions d'autres personnes au problème :)