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

你能分享一下你的想法吗?你将如何在MongoDB中实现数据版本化? (我问过关于Cassandra的类似问题,如果你有任何想法,哪个db更好,请分享)

假设我需要在简单的地址簿中记录版本记录。 (地址簿记录存储为扁平json对象)。 我期待的历史:

  • 将很少使用
  • 将一次全部使用,以“时间机器”的方式呈现
  • 不会有更多的版本比几百到一个单一的记录。 历史不会过期。
  • 我正在考虑以下方法:

  • 创建一个新的对象集合来存储记录的历史或对记录的更改。 它将在每个版本中存储一个对象,并引用地址簿条目。 这些记录如下所示:

    {
     '_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' ...}
    }
    

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

  • 将版本存储为附加到地址簿条目的序列化(JSON)对象。 我不确定如何将这些对象附加到MongoDB文档。 也许是一串字符串。 (使用CouchDB进行简单文档版本控制后进行建模)


  • 第一个大问题是,“如何存储变更集”?

  • 比较速度?
  • 整个记录副本?
  • 我个人的做法是存储差异。 由于这些差异的显示确实是一个特殊的行为,我会将差异放在不同的“历史”集合中。

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

    为了让我的生活更轻松,我会让历史文档包含时间戳差异字典。 像这样的东西:

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

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

    更新:2015-10

    它看起来像现在有一个处理JSON差异的规范。 这似乎是一种更强大的方式来存储差异/变化。


    有一个名为“Vermongo”的版本控制方案,它解决了其他答复中尚未处理的一些方面。

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

    Vermongo将完整的文档副本存储在影集中。 对于某些使用情况来说,这可能会造成太多的开销,但我认为这也简化了很多事情。

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


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

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

    data包含所有版本。 data数组是有序的 ,新版本将只获得$push到数组的末尾。 data.vid是版本ID,它是一个递增的数字。

    获取最新版本:

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

    通过vid获取特定版本:

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

    仅返回指定的字段:

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

    插入新版本:(并阻止并发插入/更新)

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

    2是当前最新版本的vid3是插入的新版本。 因为你需要最新版本的vid ,所以很容易获得下一个版本的vidnextVID = oldVID + 1

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

    这样就不需要唯一的索引,但应用程序逻辑必须注意在插入时增加vid

    删除特定版本:

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

    而已!

    (请记住每个文档限制16MB)

    链接地址: http://www.djcxy.com/p/86371.html

    上一篇: Ways to implement data versioning in MongoDB

    下一篇: What does MongoDB not being ACID compliant really mean?