Formas de implementar el control de versiones de datos en MongoDB

Resuelto Piotr Czapla asked hace 14 años • 7 respuestas

¿Puede compartir su opinión sobre cómo implementaría el control de versiones de datos en MongoDB? (Hice una pregunta similar con respecto a Cassandra . Si tiene alguna idea sobre qué base de datos es mejor para eso, compártala)

Supongamos que necesito versionar registros en una libreta de direcciones simple. (Los registros de la libreta de direcciones se almacenan como objetos json planos). Espero que la historia:

  • se usará con poca frecuencia
  • se utilizará todo a la vez para presentarlo en forma de "máquina del tiempo"
  • No habrá más versiones que unos pocos cientos en un solo disco. la historia no caducará.

Estoy considerando los siguientes enfoques:

  • Cree una nueva colección de objetos para almacenar el historial de registros o cambios en los registros. Almacenaría un objeto por versión con una referencia a la entrada de la libreta de direcciones. Dichos registros tendrían el siguiente aspecto:

    {
     '_id': 'nueva identificación',
     'usuario': id_usuario,
     'marca de tiempo': marca de tiempo,
     'address_book_id': 'id del registro de la libreta de direcciones'
     'old_record': {'first_name': 'Jon', 'last_name':'Doe' ...}
    }
    

    Este enfoque se puede modificar para almacenar una variedad de versiones por documento. Pero este parece ser un enfoque más lento y sin ventajas.

  • Almacene las versiones como objetos serializados (JSON) adjuntos a las entradas de la libreta de direcciones. No estoy seguro de cómo adjuntar dichos objetos a documentos MongoDB. Quizás como una serie de cuerdas. ( Modelado a partir del control de versiones de documentos simples con CouchDB )

Piotr Czapla avatar Nov 15 '10 21:11 Piotr Czapla
Aceptado

La primera gran pregunta al profundizar en esto es "¿cómo desea almacenar los conjuntos de cambios ? "

  1. ¿Diferencias?
  2. ¿Copias de discos completos?

Mi enfoque personal sería almacenar diferencias. Debido a que la visualización de estas diferencias es realmente una acción especial, yo colocaría las diferencias en una colección de "historia" diferente.

Usaría la colección diferente para ahorrar espacio en la memoria. Por lo general, no desea un historial completo para una consulta simple. Entonces, al mantener el historial fuera del objeto, también puede mantenerlo fuera de la memoria a la que se accede comúnmente cuando se consultan esos datos.

Para hacerme la vida más fácil, haría que un documento histórico contuviera un diccionario de diferencias con marca de tiempo. Algo como esto:

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

Para hacerme la vida realmente más fácil, haría esta parte de mis DataObjects (EntityWrapper, lo que sea) que uso para acceder a mis datos. Generalmente estos objetos tienen algún tipo de historial, por lo que puedes anular fácilmente el save()método para realizar este cambio al mismo tiempo.

ACTUALIZACIÓN: 2015-10

Parece que ahora hay una especificación para manejar diferencias JSON . Esta parece una forma más sólida de almacenar las diferencias/cambios.

Gates VP avatar Nov 15 '2010 22:11 Gates VP

Existe un esquema de versiones llamado "Vermongo" que aborda algunos aspectos que no se han tratado en las otras respuestas.

Uno de estos problemas son las actualizaciones simultáneas, otro es la eliminación de documentos.

Vermongo almacena copias completas de documentos en una colección paralela. Para algunos casos de uso, esto puede causar demasiada sobrecarga, pero creo que también simplifica muchas cosas.

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

Marian avatar Oct 27 '2012 09:10 Marian

Aquí hay otra solución que utiliza un único documento para la versión actual y todas las versiones anteriores:

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

datacontiene todas las versiones. La datamatriz está ordenada , las nuevas versiones solo llegarán $pushal final de la matriz. data.vides la identificación de la versión, que es un número creciente.

Obtenga la versión más reciente:

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

Obtenga una versión específica mediante vid:

find(
    { "_id":ObjectId("...") },
    { "data":{ $elemMatch:{ "vid":1 } } }
)

Devuelve sólo los campos especificados:

find(
    { "_id":ObjectId("...") },
    { "data":{ $elemMatch:{ "vid":1 } }, "data.content":1 }
)

Insertar nueva versión: (y evitar inserción/actualización simultánea)

update(
    {
        "_id":ObjectId("..."),
        $and:[
            { "data.vid":{ $not:{ $gt:2 } } },
            { "data.vid":2 }
        ]
    },
    { $push:{ "data":{ "vid":3, "content":"baz" } } }
)

2es el vidde la versión más reciente y 3es la nueva versión que se está insertando. Debido a que necesita la versión más reciente vid, es fácil obtener la siguiente versión vid: nextVID = oldVID + 1.

La $andcondición garantizará que 2sea la última vid.

De esta manera no es necesario un índice único, pero la lógica de la aplicación debe encargarse de incrementar la vidinserción.

Eliminar una versión específica:

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

¡Eso es todo!

(recuerde el límite de 16 MB por documento)

Benjamin M avatar Mar 14 '2015 04:03 Benjamin M