321 votes

Façons d'implémenter le versioning des données dans MongoDB

Pouvez-vous nous faire part de vos réflexions sur la manière de mettre en œuvre le versioning des données dans MongoDB ? (J'ai demandé question similaire concernant Cassandra . Si vous avez une idée de la meilleure base de données pour cela, veuillez la partager.)

Supposons que j'aie besoin de versionner des enregistrements dans un carnet d'adresses simple. (Les enregistrements du carnet d'adresses sont stockés sous forme d'objets json plats). Je m'attends à ce que l'historique :

  • ne sera pas utilisé fréquemment
  • sera utilisé en une seule fois pour le présenter à la manière d'une "machine à remonter le temps".
  • il n'y aura pas plus de versions que quelques centaines pour un seul enregistrement. L'historique n'expirera pas.

J'envisage les approches suivantes :

  • Créez une nouvelle collection d'objets pour stocker l'historique des enregistrements ou des modifications apportées aux enregistrements. Elle stockera un objet par version avec une référence à l'entrée du carnet d'adresses. Ces enregistrements se présenteraient comme suit :

    {
     '\_id': 'new id',
     'user': user\_id,
     'timestamp': timestamp,
     'address\_book\_id': 'id of the address book record' 
     '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.

  • Stocker les versions sous forme d'objet sérialisé (JSON) attaché aux entrées du carnet d'adresses. Je ne sais pas comment attacher de tels objets aux documents MongoDB. Peut-être sous la forme d'un tableau de chaînes de caractères. ( Calqué sur le modèle du versionnement simple de documents avec CouchDB )

1 votes

Je voudrais savoir si cela a changé depuis la réponse à la question ? Je ne m'y connais pas beaucoup en oplog, mais si cela existait à l'époque, cela ferait-il une différence ?

0 votes

Mon approche consiste à considérer toutes les données comme une série chronologique.

163voto

Gates VP Points 26481

La première grande question à se poser est la suivante "comment voulez-vous stocker les changesets" ?

  1. Diffs ?
  2. Des copies entières de disques ?

Mon approche personnelle serait de stocker les différences. Comme l'affichage de ces diffs est vraiment une action spéciale, je mettrais les diffs dans une collection "historique" différente.

J'utiliserais les différentes collections pour gagner de l'espace mémoire. Vous ne voulez généralement pas un historique complet pour une simple requête. Ainsi, en gardant l'historique en dehors de l'objet, vous pouvez également le garder en dehors de la mémoire couramment utilisée lorsque ces données sont interrogées.

Pour me faciliter la vie, je ferais en sorte qu'un document d'historique contienne un dictionnaire de diffs horodatés. Quelque chose comme ça :

{
    _id : "id of address book record",
    changes : { 
                1234567 : { "city" : "Omaha", "state" : "Nebraska" },
                1234568 : { "city" : "Kansas City", "state" : "Missouri" }
               }
}

Pour me faciliter la vie, je ferais en sorte que cet objet fasse partie de mes DataObjects (EntityWrapper, peu importe) que j'utilise pour accéder à mes données. Généralement, ces objets ont une certaine forme d'historique, de sorte que vous pouvez facilement remplacer la fonction save() pour effectuer ce changement en même temps.

MISE À JOUR : 2015-10

Il semble qu'il y ait maintenant une spécification pour la gestion des différences JSON . Cela semble être un moyen plus robuste de stocker les différences / changements.

2 votes

Ne craignez-vous pas qu'un tel document d'histoire (l'objet modifications) s'étoffe avec le temps et que les mises à jour deviennent inefficaces ? Ou bien MongoDB gère-t-il facilement la croissance des documents ?

5 votes

Regardez le montage. Ajouté à changes est très facile : db.hist.update({_id: ID}, {$set { changes.12345 : CHANGES } }, true) Cela permettra d'effectuer un upsert qui ne modifiera que les données requises. Mongo crée des documents avec un "espace tampon" pour gérer ce type de changement. Il observe également comment les documents d'une collection changent et modifie la taille de la mémoire tampon pour chaque collection. MongoDB est donc conçu exactement pour ce type de changement (ajout d'une nouvelle propriété / push to array).

2 votes

J'ai effectué quelques tests et, en effet, la réservation d'espace fonctionne plutôt bien. Je n'ai pas réussi à détecter la perte de performance lorsque les enregistrements ont été réaffectés à la fin du fichier de données.

33voto

Marian Points 488

Il existe un système de gestion des versions appelé "Vermongo" qui traite de certains aspects qui n'ont pas été abordés dans les autres réponses.

L'un de ces problèmes est celui des mises à jour simultanées, un autre celui de la suppression de documents.

Vermongo stocke des copies complètes de documents dans une collection fantôme. Pour certains cas d'utilisation, cela peut entraîner une surcharge trop importante, mais je pense que cela simplifie également beaucoup de choses.

https://github.com/thiloplanz/v7files/wiki/Vermongo

5 votes

Comment l'utilisez-vous concrètement ?

6 votes

Il n'existe aucune documentation sur la manière dont ce projet est réellement utilisé. Est-ce quelque chose qui vit avec Mongo en quelque sorte ? C'est une bibliothèque Java ? Est-ce simplement une façon de penser au problème ? Aucune idée et aucune indication n'est donnée.

1 votes

Il s'agit en fait d'une application Java et le code pertinent se trouve ici : github.com/thiloplanz/v7files/blob/master/src/main/java/v7db/

28voto

Benjamin M Points 2206

Voici une autre solution utilisant un document unique pour la version actuelle et toutes les anciennes versions :

{
    _id: ObjectId("..."),
    data: [
        { vid: 1, content: "foo" },
        { vid: 2, content: "bar" }
    ]
}

data contient tous versions. Le site data Le tableau est commandé les nouvelles versions ne recevront que $push à la fin du tableau. data.vid est l'identifiant de la version, qui est un nombre incrémentiel.

Obtenez la version la plus récente :

find(
    { "_id":ObjectId("...") },
    { "data":{ $slice:-1 } }
)

Obtenez une version spécifique en 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 le vid de la version actuelle la plus récente et 3 c'est la nouvelle version qui est insérée. Parce que vous avez besoin de la version la plus récente vid il est facile d'obtenir la prochaine version de vid : nextVID = oldVID + 1 .

El $and Cette condition permettra de garantir que 2 est le dernier vid .

De cette façon, il n'est pas nécessaire d'avoir un index unique, mais la logique de l'application doit s'occuper d'incrémenter l'indexation de l'indexation. vid sur l'insert.

Supprimer une version spécifique :

update(
    { "_id":ObjectId("...") },
    { $pull:{ "data":{ "vid":2 } } }
)

C'est ça !

(n'oubliez pas la limite de 16 Mo par document)

14voto

s01ipsist Points 1104

Si vous êtes à la recherche d'une solution prête à l'emploi -

Mongoid intègre un système de gestion des versions simple

http://mongoid.org/en/mongoid/docs/extras.html#versioning

mongoid-history est un plugin Ruby qui fournit une solution beaucoup plus complexe avec audit, undo et redo.

https://github.com/aq1018/mongoid-history

19 votes

Pour le langage de programmation ruby.

10voto

Daniel Watrous Points 178

J'ai travaillé sur cette solution qui prend en compte les versions publiées, provisoires et historiques des données :

{
  published: {},
  draft: {},
  history: {
    "1" : {
      metadata: <value>,
      document: {}
    },
    ...
  }
}

J'explique ce modèle plus en détail ici : http://software.danielwatrous.com/representing-revision-data-in-mongodb/

Pour ceux qui pourraient implémenter quelque chose comme cela dans Java Voici un exemple :

http://software.danielwatrous.com/using-java-to-work-with-versioned-data/

Y compris tout le code que vous pouvez bifurquer, si vous le souhaitez.

https://github.com/dwatrous/mongodb-revision-objects

0 votes

C'est génial :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X