MongoDB / NoSQL:保持文档更改历史记录

数据库应用程序中一个相当常见的需求是跟踪对数据库中一个或多个特定实体的更改。 我听说过所谓的行版本控制,日志表或历史表(我确定还有其他名字)。 在RDBMS中有很多方法可以处理它 - 您可以将所有源表中的所有更改写入单个表(更多日志)或为每个源表创建单独的历史记录表。 您还可以选择管理应用程序代码中的日志记录或通过数据库触发器进行管理。

我试图通过对NoSQL /文档数据库(特别是MongoDB)中相同问题的解决方案进行思考,以及如何以统一的方式解决该问题。 它会像为文档创建版本号一样简单,并且从不覆盖它们? 为“真实”与“已记录”文档创建单独的集合? 这会如何影响查询和性能?

无论如何,这是NoSQL数据库的常见情况,如果是这样,是否有一个通用的解决方案?


好问题,我自己也在研究这个问题。

每次更改都创建一个新版本

我遇到了Ruby的Mongoid驱动程序的Versioning模块。 我自己并没有使用它,但是从我所能找到的内容中,它为每个文档添加了一个版本号。 较早的版本嵌入在文档本身中。 主要缺点是每次更改都会复制整个文档 ,这会导致在处理大型文档时会存储大量重复内容。 尽管处理小尺寸文档和/或不经常更新文档,但这种方法没问题。

只能将更改存储在新版本中

另一种方法是仅将更改的字段存储在新版本中 。 然后,您可以“平放”历史记录以重建任何版本的文档。 但这很复杂,因为您需要跟踪模型中的更改并以应用程序可以重新构建最新文档的方式存储更新和删除。 这可能会非常棘手,因为您正在处理结构化文档而不是平坦的SQL表格。

将更改存储在文档中

每个领域也可以有个人历史。 以这种方式更容易地将文档重建为给定版本。 在您的应用程序中,您不必显式跟踪更改,但只需在更改其值时创建新版本的属性。 文档可能看起来像这样:

{
  _id: "4c6b9456f61f000000007ba6"
  title: [
    { version: 1, value: "Hello world" },
    { version: 6, value: "Foo" }
  ],
  body: [
    { version: 1, value: "Is this thing on?" },
    { version: 2, value: "What should I write?" },
    { version: 6, value: "This is the new body" }
  ],
  tags: [
    { version: 1, value: [ "test", "trivial" ] },
    { version: 6, value: [ "foo", "test" ] }
  ],
  comments: [
    {
      author: "joe", // Unversioned field
      body: [
        { version: 3, value: "Something cool" }
      ]
    },
    {
      author: "xxx",
      body: [
        { version: 4, value: "Spam" },
        { version: 5, deleted: true }
      ]
    },
    {
      author: "jim",
      body: [
        { version: 7, value: "Not bad" },
        { version: 8, value: "Not bad at all" }
      ]
    }
  ]
}

将文档的部分标记为在版本中删除仍然有些尴尬。 您可以为可从应用程序中删除/恢复的零件引入一个state字段:

{
  author: "xxx",
  body: [
    { version: 4, value: "Spam" }
  ],
  state: [
    { version: 4, deleted: false },
    { version: 5, deleted: true }
  ]
}

通过这些方法,您可以将最新的扁平版本存储在一个集合中,并将历史数据存储在单独的集合中。 如果您只对最新版本的文档感兴趣,这应该会改善查询时间。 但是当你需要最新版本和历史数据时,你需要执行两个查询,而不是一个查询。 因此,使用单个集合与两个单独集合的选择应取决于应用程序需要多久的历史版本

这个答案中的大部分只是我思想的大脑转储,实际上我还没有尝试过。 回顾一下,第一种选择可能是最简单和最好的解决方案,除非重复数据的开销对于您的应用程序非常重要。 第二种选择非常复杂,可能不值得。 第三个选项基本上是选项二的优化,应该更容易实现,但可能不值得执行的努力,除非你真的不能选择一个。

期待对此的反馈,以及其他人对问题的解决方案:)


我们已经在我们的网站上部分实现了这个功能,并且我们使用'在一个单独的文档中存储修订版本'(以及单独的数据库)。我们编写了一个自定义函数来返回差异数据并存储它。


为什么Store上的变体不会在文档中发生变化

不是按照每个密钥对存储版本,文档中的当前密钥对始终代表最近的状态,并且更改的“日志”存储在历史数组中。 只有那些自创建以来已更改的密钥才会在日志中有条目。

{
  _id: "4c6b9456f61f000000007ba6"
  title: "Bar",
  body: "Is this thing on?",
  tags: [ "test", "trivial" ],
  comments: [
    { key: 1, author: "joe", body: "Something cool" },
    { key: 2, author: "xxx", body: "Spam", deleted: true },
    { key: 3, author: "jim", body: "Not bad at all" }
  ],
  history: [
    { 
      who: "joe",
      when: 20160101,
      what: { title: "Foo", body: "What should I write?" }
    },
    { 
      who: "jim",
      when: 20160105,
      what: { tags: ["test", "test2"], comments: { key: 3, body: "Not baaad at all" }
    }
  ]
}
链接地址: http://www.djcxy.com/p/15155.html

上一篇: MongoDB/NoSQL: Keeping Document Change History

下一篇: How to query MongoDB with "like"?