首页 文章

在MongoDB中实现数据版本控制的方法

提问于
浏览
266

您能否分享一下您如何在MongoDB中实现数据版本控制? (我已经问了similar question regarding Cassandra . 如果您有任何想法,哪个数据库更好,请分享)

假设我需要在简单的地址簿中对记录进行版本控制 . (地址簿记录存储为平面json对象) . 我期待历史:

  • 将不经常使用

  • 将一次性使用以"time machine"方式呈现它

  • 赢了't be more versions than few hundred to a single record. history won'吨到期 .

我正在考虑以下方法:

  • 创建新的对象集合以存储记录的历史记录或记录的更改 . 它将为每个版本存储一个对象,并引用地址簿条目 . 这些记录如下:
{
 '_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' ...}
}

可以修改此方法以存储每个文档的版本数组 . 但这似乎是没有任何优势的较慢的方法 .

9 回答

  • 9

    有一种称为“Vermongo”的版本控制方案,它解决了其他答复中未涉及的一些方面 .

    其中一个问题是并发更新,另一个是删除文档 .

    Vermongo将完整的文档副本存储在阴影集合中 . 对于某些用例,这可能会导致过多的开销,但我认为它也简化了很多事情 .

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

  • 18

    潜入这个问题的第一个重要问题是"how do you want to store changesets"?

    • Diffs?

    • 整个记录副本?

    我个人的方法是存储差异 . 因为这些差异的显示实际上是一个特殊的动作,我会把差异放在一个不同的“历史”集合中 .

    我会使用不同的集合来节省内存空间 . 您通常不希望简单查询的完整历史记录 . 因此,通过将历史记录保留在对象之外,您还可以在查询数据时将其保留在常用内存中 .

    为了让我的生活变得轻松,我会制作一份包含时间标记差异字典的历史文档 . 像这样的东西:

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

    为了让我的生活变得非常简单,我将使用我用来访问我的数据的DataObjects(EntityWrapper,无论如何) . 通常,这些对象具有某种形式的历史记录,因此您可以轻松地覆盖 save() 方法以同时进行此更改 .

    UPDATE: 2015-10

    看起来现在有a spec for handling JSON diffs . 这似乎是一种更健壮的方式来存储差异/变化 .

  • 29

    这是针对当前版本和所有旧版本使用单个文档的另一种解决方案:

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

    data 包含 all 版本 . data 数组是 ordered ,新版本只能在数组末尾获得 $push . data.vid 是版本ID,是递增的数字 .

    Get the most recent version:

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

    Get a specific version by vid:

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

    Return only specified fields:

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

    Insert new version: (并防止并发插入/更新)

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

    2 是当前最新版本的 vid3 是插入的新版本 . 因为您需要最新版本的 vid ,所以's easy to do get the next version' s vidnextVID = oldVID + 1 .

    $and 条件将确保 2 是最新的 vid .

    这种方式不需要唯一索引,但应用程序逻辑必须注意增加插入 vid .

    Remove a specific version:

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

    而已!

    (记住每个文件限制16MB)

  • 3

    如果您正在寻找即时解决方案 -

    Mongoid内置了简单版本

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

    mongoid-history是一个Ruby插件,它提供了一个复杂的解决方案,包括审计,撤销和重做

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

  • 136

    我通过这个解决方案来处理数据的已发布,草稿和历史版本:

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

    我在这里进一步解释模型:http://software.danielwatrous.com/representing-revision-data-in-mongodb/

    对于那些可能在 Java 中实现类似内容的人,这是一个例子:

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

    如果你愿意,可以包括你可以分叉的所有代码

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

  • 12

    如果您使用的是mongoose,我发现以下插件是JSON Patch格式的有用实现

    mongoose-patch-history

  • -2

    另一种选择是使用mongoose-history插件 .

    let mongoose = require('mongoose');
    let mongooseHistory = require('mongoose-history');
    let Schema = mongoose.Schema;
    
    let MySchema = Post = new Schema({
        title: String,
        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.
    
  • 1

    我使用下面的包用于meteor / MongoDB项目,它运行良好,主要优点是它将数据库中的历史/修订存储在同一文档中,因此无需额外的出版物或中间件来访问更改历史记录 . 它可以支持有限数量的先前版本(例如前十个版本),它还支持更改连接(因此在特定时间段内发生的所有更改都将由一个修订版覆盖) .

    nicklozon/meteor-collection-revisions

    另一个声音选项是使用Meteor Vermongo(here

  • 2

    尝试使用Javers . 好图书馆 .

相关问题