MongoDB中数据版本化的实现方法

q9rjltbz  于 2023-03-07  发布在  Go
关注(0)|答案(9)|浏览(460)

你能分享一下你的想法吗?你将如何在MongoDB中实现数据版本控制?(我问过similar question regarding Cassandra。如果你有任何想法,哪个数据库更适合,请分享)
假设我需要对一个简单的地址簿中的记录进行版本控制(地址簿记录存储为扁平的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' ...}
}

这种方法可以修改为每个文档存储一个版本数组,但是这种方法似乎比较慢,没有任何优点。

gfttwv5a

gfttwv5a1#

第一个大问题是 “您希望如何存储变更集”
1.分歧?
1.整张唱片的拷贝?
我个人的方法是存储差异。因为这些差异的显示确实是一个特殊的操作,我会把差异放在不同的“历史”集合中。
我会使用不同的集合来保存内存空间。通常,对于简单的查询,您不需要完整的历史记录。因此,通过将历史记录保存在对象之外,您也可以在查询数据时将其保存在经常访问的内存之外。
为了让我的工作更轻松,我会让历史文档包含一个带有时间戳的差异字典。

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

为了让我的生活变得更轻松,我会将这一部分作为DataObjects(EntityWrapper,不管是什么)的一部分,用于访问我的数据。通常,这些对象具有某种形式的历史记录,因此您可以轻松地覆盖save()方法,以便同时进行更改。

更新日期:2015年10月

看起来现在有了a spec for handling JSON diffs。这似乎是一种更健壮的存储差异/更改的方法。

ijnw1ujt

ijnw1ujt2#

有一个称为“Vermongo”的版本控制方案,它解决了其他答复中没有处理的一些方面。
其中一个问题是并发更新,另一个问题是删除文档。
Vermongo将完整的文档副本存储在一个影子集合中。对于某些用例,这可能会导致太多的开销,但我认为它也简化了许多事情。
https://github.com/thiloplanz/v7files/wiki/Vermongo

yzckvree

yzckvree3#

下面是另一个解决方案,它使用一个文档来处理当前版本和所有旧版本:

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

data包含所有版本。data数组是有序的,新版本将仅获得添加到数组末尾的$pushdata.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的限制)*
cygmwpex

cygmwpex4#

如果您正在寻找现成的解决方案-
Mongoid内置了简单的版本控制
http://mongoid.org/en/mongoid/docs/extras.html#versioning
mongoid-history是一个Ruby插件,它提供了一个复杂得多的解决方案,包括审计、撤消和重做
https://github.com/aq1018/mongoid-history

ctzwtxfj

ctzwtxfj5#

我使用了这个解决方案,它可以容纳数据的已发布版本、草稿版本和历史版本:

{
  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

ecr0jaav

ecr0jaav6#

如果您正在使用mongoose,我发现下面的插件是JSON Patch的一个有用的实现
mongoose-patch-history

tp5buhyn

tp5buhyn7#

另一种选择是使用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.
qncylg1j

qncylg1j8#

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

fruv7luv

fruv7luv9#

你可以试试javers我没有找到任何更好的解决方案,直到现在https://javers.org/

相关问题