Mongodb:带搜索的数据版本控制



在MongoDB中实现数据版本控制的方法以及在MongoDB 上对时间序列进行版本控制的文档结构

当我还需要能够处理查询时,我应该采用什么数据结构来进行版本控制

假设我有8500份格式的文件

{ _id: '12345-11',
  noFTEs: 5
}

每个月,我都会在大约30个文档中获得noFTEs更改的详细信息,我想将新数据与前一个数据一起存储,并附上日期。

这似乎会导致:

{ _id: '12345-11',
  noFTEs: {
     '2015-10-28T00:00:00+01:00': 5,
     '2015-1-8T00:00:00+01:00': 3
  }
}

但我也希望能够对最新的数据进行搜索(例如noFTEs > 4,并且元素应该被认为是5,而不是3)。在那个阶段,我只知道我想使用最新的数据,而不会知道关键。因此,一种替代方案是阵列

{ _id: '12345-11',
  noFTEs: [
     {date: '2015-10-28T00:00:00+01:00', val: 5},
     {date: '2015-1-8T00:00:00+01:00', val: 3}
  }
}

另一种选择是,正如@thomasbormans在下面的评论中所建议的那样

{ _id: '12345-11',
  versions: [
     {noFTEs: 5, lastModified: '2015-10-28T00:00:00+01:00', other data...},
     {noFTEs: 3, lastModified: '2015-1-8T00:00:00+01:00', other...}
  }
}

我真的很感激在一路跳进去之前对我需要考虑的问题有一些见解,我担心我会产生一个对Mongo来说相当高的工作量的查询。(在实践中,还有3个其他字段可以组合进行搜索,其中一个字段也可能随着时间的推移而发生变化。)

当您为noSQL数据库建模时,需要记住一些事情。

首先是每个文档的大小。如果您在文档中使用数组,请确保它不会超过每个文档的16Mb大小限制。

第二件事,您必须为数据库建模,以便轻松检索内容。一些"非规范化"是可以接受的,有利于您的应用程序的速度和易用性。

因此,如果您需要知道当前的noFTE值,并且只为了审计目的而需要保留历史记录,则可以使用两个集合:

collection["current"] = [
    {
        _id: '12345-11',
        noFTEs: 5, 
        lastModified: '2015-10-28T00:00:00+01:00'
    }
]
collection["history"] = [
    {   _id: ...an object id...
        source_id: '12345-11',
        noFTEs: 5, 
        lastModified: '2015-10-28T00:00:00+01:00'
    },
    {
        _id: ...an object id...
        source_id: '12345-11',
        noFTEs: 3, 
        lastModified: '2015-1-8T00:00:00+01:00'
    }
]

通过这种方式,您可以将最频繁访问的记录保持得更小(我认为当前版本的访问频率更高)。这将使mongo更倾向于将"当前"集合保存在内存缓存中。而且从磁盘中检索文档的速度会更快,因为它们更小。

我觉得这个设计在内存优化方面是最好的。但这个决定直接关系到你将如何使用你的数据。

编辑:我更改了最初的响应,以便为每个历史条目创建单独的插入。在我最初的回答中,我试图使您的历史记录条目接近您的原始解决方案,以集中于非规范化主题。然而,将历史记录保存在一个数组中是一个糟糕的设计决定,我决定让这个答案更完整。

在历史中保留分离插入而不是创建数组的选择有很多:

1) 每当您更改文档的大小(例如,向其中插入更多数据)时,mongo可能需要将此文档移动到磁盘的空白部分,以便容纳更大的文档。这样,您最终会造成存储缺口,从而使您的收藏变得更大。

2) 每当你插入一个新文档时,Mongo都会根据之前的插入/更新来预测它的大小。这样,如果您的历史文档的大小相似,则填充因子将接近最优。然而,当您保持增长的数组时,这种预测将不好,mongo将通过填充来浪费空间。

3) 在未来,如果你的历史收藏变得太大,你可能会想缩小它。通常,我们定义了一个历史记录保留策略(例如:5年),您可以备份和修剪超过该策略的数据。如果您为每个历史记录条目保留了单独的文档,那么执行此操作会容易得多。

我可以找到其他原因,但我相信这三个原因足以说明问题。

要在不影响最新数据的可用性和访问速度的情况下添加版本控制,请考虑创建两个集合:一个包含最新文档,另一个用于在文档更改时存档旧版本。

您可以使用currentVersionCollection.findAndModify更新文档,同时在一个命令中接收所述文档的以前版本(或新版本,具体取决于参数)。然后,您只需要删除返回文档的_id,添加时间戳和/或修订号(如果您还没有这些),并将其插入存档集合中。

通过将每个旧版本存储在自己的文档中,您还可以避免文档增长,并防止文档在发生大量更改时超过16MB的文档限制。

最新更新