Pouvez-vous partager vos reflections sur la manière dont vous metsortingez en œuvre la gestion des versions de données dans MongoDB. (J’ai posé une question similaire à propos de Cassandra . Si vous avez des idées qui db est mieux pour cela, veuillez partager)
Supposons que je doive enregistrer des versions dans un carnet d’adresses simple. (Les enregistrements du carnet d’adresses sont stockés sous forme d’objects plats json). Je m’attends à ce que l’histoire:
Je considère les approches suivantes:
Créez une nouvelle collection d’objects pour stocker l’historique des enregistrements ou les modifications apscopes aux enregistrements. Il stockerait un object par version avec une référence à l’entrée du carnet d’adresses. Ces enregistrements ressembleraient à ceci:
{ '_id': 'nouvel identifiant', 'user': user_id, 'horodatage': horodatage, 'address_book_id': 'identifiant de l'enregistrement du carnet d'adresses' 'old_record': {'first_name': 'Jon', 'last_name': 'Doe' ...} }
Cette approche peut être modifiée pour stocker un tableau de versions par document. Mais cela semble être une approche plus lente sans aucun avantage.
Stockez les versions en tant qu’object sérialisé (JSON) associé aux entrées du carnet d’adresses. Je ne sais pas comment joindre de tels objects aux documents MongoDB. Peut-être comme un tableau de chaînes. ( Modélisé après le contrôle de version de document simple avec CouchDB )
La première grande question à poser est la suivante: “comment voulez-vous stocker les changesets” ?
Mon approche personnelle serait de stocker les diffs. Parce que l’affichage de ces diffs est vraiment une action spéciale, je placerais les diffs dans une collection “historique” différente.
J’utiliserais la collection différente pour économiser de l’espace mémoire. Vous ne voulez généralement pas un historique complet pour une requête simple. Ainsi, en gardant l’historique hors de l’object, vous pouvez également le garder hors de la mémoire communément utilisée lorsque ces données sont interrogées.
Pour faciliter ma vie, je ferais un document d’historique contenant un dictionnaire de diffs horodatés. Quelque chose comme ça:
{ _id : "id of address book record", changes : { 1234567 : { "city" : "Omaha", "state" : "Nearmka" }, 1234568 : { "city" : "Kansas City", "state" : "Missouri" } } }
Pour rendre ma vie vraiment facile, je ferais cette partie de mes DataObjects (EntityWrapper, peu importe) que j’utilise pour accéder à mes données. En général, ces objects ont une forme d’histoire, de sorte que vous pouvez facilement remplacer la méthode save()
pour effectuer cette modification en même temps.
MISE À JOUR: 2015-10
Il semble qu’il y ait maintenant une spécification pour gérer les diff JSON . Cela semble être un moyen plus robuste de stocker les diffs / modifications.
Il existe un système de gestion des versions appelé “Vermongo” qui aborde certains aspects qui n’ont pas été traités dans les autres réponses.
L’une de ces questions concerne les mises à jour simultanées, une autre consiste à supprimer des documents.
Vermongo stocke des copies complètes de documents dans une collection fantôme. Pour certains cas d’utilisation, cela pourrait entraîner trop de frais généraux, mais je pense que cela simplifie également beaucoup de choses.
Voici une autre solution utilisant un seul document pour la version actuelle et toutes les anciennes versions:
{ _id: ObjectId("..."), data: [ { vid: 1, content: "foo" }, { vid: 2, content: "bar" } ] }
data
contiennent toutes les versions. Le tableau de data
est ordonné , les nouvelles versions n’obtiendront que $push
à la fin du tableau. data.vid
est l’identifiant de la version, qui est un nombre incrémenté.
Obtenez la version la plus récente:
find( { "_id":ObjectId("...") }, { "data":{ $slice:-1 } } )
Obtenez une version spécifique par vid
:
find( { "_id":ObjectId("...") }, { "data":{ $elemMatch:{ "vid":1 } } } )
Renvoie uniquement les champs spécifiés:
find( { "_id":ObjectId("...") }, { "data":{ $elemMatch:{ "vid":1 } }, "data.content":1 } )
Insérer une nouvelle version: (et empêcher l’insertion / mise à jour simultanée)
update( { "_id":ObjectId("..."), $and:[ { "data.vid":{ $not:{ $gt:2 } } }, { "data.vid":2 } ] }, { $push:{ "data":{ "vid":3, "content":"baz" } } } )
2
est la vid
de la version la plus récente et 3
est la nouvelle version à insérer. Comme vous avez besoin de la version la plus récente de la version, il est facile de récupérer la vid
de la prochaine version: nextVID = oldVID + 1
.
Le $and
condition assureront que 2
est la dernière vid
.
De cette façon, vous n’avez pas besoin d’un index unique, mais la logique de l’application doit faire en sorte d’incrémenter l’insertion vid
.
Supprimer une version spécifique:
update( { "_id":ObjectId("...") }, { $pull:{ "data":{ "vid":2 } } } )
C’est tout!
(rappelez-vous la limite de 16 Mo par document)
Si vous recherchez une solution prête à l’emploi –
Mongoid a construit en versioning simple
http://mongoid.org/en/mongoid/docs/extras.html#versioning
mongoid-history est un plugin Ruby qui fournit une solution beaucoup plus compliquée avec l’audit, l’annulation et la restauration
J’ai travaillé sur cette solution qui intègre une version publiée, une version brouillon et une version historique des données:
{ published: {}, draft: {}, history: { "1" : { metadata: , document: {} }, ... } }
J’explique le modèle plus loin ici: http://software.danielwatrous.com/representing-revision-data-in-mongodb/
Pour ceux qui peuvent implémenter quelque chose comme ça en Java , voici un exemple:
http://software.danielwatrous.com/using-java-to-work-with-versenced-data/
Y compris tout le code que vous pouvez bifurquer, si vous voulez
Si vous utilisez mongoose, le plug-in suivant est une implémentation utile du format JSON Patch
histoire de patch-mongoose
Une autre option consiste à utiliser le plugin mongoose-history .
let mongoose = require('mongoose'); let mongooseHistory = require('mongoose-history'); let Schema = mongoose.Schema; let MySchema = Post = new Schema({ title: Ssortingng, status: Boolean }); MySchema.plugin(mongooseHistory); // The plugin will automatically create a new collection with the schema name + "_history". // In this case, collection with name "my_schema_history" will be created.
J’ai utilisé le package ci-dessous pour un projet meteor / MongoDB, et cela fonctionne bien, le principal avantage est qu’il stocke l’historique / les révisions dans un tableau du même document, donc pas besoin de publications ou de middleware supplémentaires pour accéder à l’historique des modifications . Il peut prendre en charge un nombre limité de versions précédentes (par exemple, les dix dernières versions), il prend également en charge la concaténation des modifications (de sorte que toutes les modifications apscopes au cours d’une période donnée seront couvertes par une révision).
nicklozon / meteor-collection-révisions
Une autre option sonore consiste à utiliser Meteor Vermongo ( ici )
Essayez d’utiliser Javers. Bonne bibliothèque