与Ways to implement data versioning in MongoDB和structure of documents for versioning of a time series on 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个其他字段可以组合进行搜索,其中一个字段也可能会随着时间的推移而发生变化。)
答案 0 :(得分:2)
当你为noSQL数据库建模时,你需要记住一些事情。
首先是每个文件的大小。如果您在文档中使用数组,请确保它不会为每个文档传递16 Mb大小限制。
其次,您必须为数据库建模以便轻松检索。一些"非规范化"是可以接受的,有利于您的申请的速度和易用性。
因此,如果您需要知道当前的noFTE值,并且您需要将历史记录仅用于审计目的,那么您可以使用2个集合:
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年),您可以备份和修剪早于此的数据。如果您为每个历史记录条目保留了单独的文档,则执行此操作将更加容易。
我可以找到其他原因,但我相信这3个足以让我们明白这一点。
答案 1 :(得分:1)
要在不影响最新数据的可用性和访问速度的情况下添加版本控制,请考虑创建两个集合:一个包含最新文档,另一个用于在文档发生更改时归档旧版本。
您可以使用currentVersionCollection.findAndModify
更新文档,同时还可以在一个命令中接收所述文档的上一个(或新的,取决于参数)版本。然后,您只需要删除返回文档的_id
,添加时间戳和/或修订号(当您还没有这些时),然后将其插入到归档集合中。
通过将每个旧版本存储在自己的文档中,您还可以避免文档增长,并防止文档在发生重大更改时突破16MB文档限制。