你能分享一下你如何在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)


当前回答

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

{
  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

其他回答

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

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

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

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

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

nicklozon / meteor-collection-revisions

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

如果你正在使用mongoose,我发现下面的插件是JSON Patch格式的有用实现

mongoose-patch-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.

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

{
    _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)