你能分享一下你如何在MongoDB中实现数据版本控制的想法吗?(关于卡桑德拉,我也问过类似的问题。如果你有任何想法,哪个db更好,请分享)

假设我需要对一个简单地址簿中的记录进行版本化。(地址簿记录存储为平面json对象)。我希望历史:

是否会不经常使用 会被一次性用“时间机器”的方式呈现出来吗 一张唱片的版本不会超过几百个。 历史不会终结。

我正在考虑以下方法:

Create a new object collection to store history of records or changes to the records. It would store one object per version with a reference to the address book entry. Such records would looks as follows: { '_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' ...} } This approach can be modified to store an array of versions per document. But this seems to be slower approach without any advantages. Store versions as serialized (JSON) object attached to address book entries. I'm not sure how to attach such objects to MongoDB documents. Perhaps as an array of strings. (Modelled after Simple Document Versioning with CouchDB)


当前回答

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

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

数据包含所有版本。数据数组是有序的,新版本只会被$推到数组的末尾。数据。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是当前最新版本的vid, 3是插入的新版本。因为你需要最新版本的vid,所以很容易得到下一个版本的vid: nextVID = oldVID + 1。

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

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

删除特定版本:

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

就是这样!

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

其他回答

在深入研究这个问题时,第一个大问题是“您想如何存储变更集”?

差别吗? 完整的唱片副本?

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

我将使用不同的集合来节省内存空间。对于一个简单的查询,通常不需要完整的历史记录。因此,当数据被查询时,通过将历史记录排除在对象之外,你也可以将它排除在常用访问的内存之外。

为了简化我的工作,我将创建一个历史文档,其中包含一个带有时间戳的差异字典。就像这样:

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

为了使我的工作更加简单,我将使我的数据对象(EntityWrapper,等等)的这一部分用于访问我的数据。通常,这些对象具有某种形式的历史记录,因此您可以轻松重写save()方法来同时进行此更改。

更新:2015 - 10

现在似乎有了处理JSON差异的规范。这似乎是一种更健壮的存储差异/更改的方式。

如果你正在寻找一个现成的解决方案-

Mongoid内置了简单的版本控制

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

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

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

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

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

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

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

我已经在一个meteor/MongoDB项目中使用了下面的包,它工作得很好,主要的优点是它将历史/修订存储在同一个文档的数组中,因此不需要额外的发布或中间件来访问更改历史。它可以支持有限数量的先前版本(例如最近的十个版本),它还支持更改连接(因此在特定时期内发生的所有更改将被一个修订覆盖)。

nicklozon / meteor-collection-revisions

另一个声音选择是使用Meteor Vermongo(这里)

我通过这个解决方案,容纳了数据的公开版本、草稿版本和历史版本:

{
  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