您能否分享您的想法,如何在MongoDB中实施数据版本。 (我问过 关于卡桑德拉的类似问题. 。如果您有任何想法更好的DB,请分享)

假设我需要在简单的通讯簿中版本记录。 (地址簿记录被存储为Flat 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的简单文档版本设计建模)

有帮助吗?

解决方案

潜水时的第一个大问题是 “您想如何存储更改”?

  1. 差异?
  2. 整个记录副本?

我的个人方法是存储差异。由于这些差异的显示实际上是一个特殊的动作,所以我会将差异放在不同的“历史”集合中。

我将使用不同的集合来节省内存空间。通常,您不想要一个简单查询的完整历史记录。因此,通过将历史记录放在对象之外,您还可以在查询数据时将其排除在常见的内存之外。

为了使我的生活变得轻松,我将制作历史记录文档包含时间戳记的词典。这样的事情:

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

为了使我的生活变得非常轻松,我将使我用来访问数据的数据对象(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 数组是 订购, ,新版本只会得到 $pushed到阵列的末端。 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 是个 vid 当前最新版本和 3 是新版本被插入。因为您需要最新版本的 vid, ,很容易获得下一个版本的 vid: nextVID = oldVID + 1.

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

这样,不需要唯一的索引,但是应用程序逻辑必须照顾 vid 在插入物上。

删除特定版本:

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

而已!

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

如果您正在寻找现成的解决方案 -

Mongoid已内置简单版本操作

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

Mongoid History是一个红宝石插件,可通过审计,撤消和重做提供更复杂的解决方案

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

我通过此解决方案进行了工作,该解决方案适合数据的发布,草稿和历史版本:

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

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

对于那些可能在此中实施这样的事情的人 爪哇, ,这是一个例子:

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

包括您可以分叉的所有代码,如果您喜欢

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

如果您正在使用Mongoose,我发现以下插件是有用的实现 JSON补丁 格式

Mongoose-patch Histrestory

另一个选择是使用 猫鼬历史 插入。

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.

我已经将以下软件包用于流星/MongoDB项目,并且效果很好,主要优点是它将历史/修订存储在同一文档中的数组中,因此不需要其他出版物或中间件来访问变更历史。它可以支持有限数量的先前版本(例如最后十个版本),它还支持变更偶像(因此,所有更改发生在特定时期内,将由一个修订版涵盖)。

Nicklozon/流星收集的重新审判

另一个声音选项是使用流星vermongo(这里)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top