我一直在研究MongoDB,我理解强烈建议文档结构在插入时完全构建(预先分配),这样未来对该文档的更改不需要移动文档在磁盘上 . 这在使用$ addToSet或$ push时是否适用?
例如,假设我有以下文件:
"_id" : "rsMH4GxtduZZfxQrC",
"createdAt" : ISODate("2015-03-01T12:08:23.007Z"),
"market" : "LTC_CNY",
"type" : "recentTrades",
"data" : [
{
"date" : "1422168530",
"price" : 13.8,
"amount" : 0.203,
"tid" : "2435402",
"type" : "buy"
},
{
"date" : "1422168529",
"price" : 13.8,
"amount" : 0.594,
"tid" : "2435401",
"type" : "buy"
},
{
"date" : "1422168529",
"price" : 13.79,
"amount" : 0.594,
"tid" : "2435400",
"type" : "buy"
}
]
我正在使用以下命令之一将新对象数组( newData
)添加到 data
字段:
$ addToSet添加到数组的末尾:
Collection.update(
{ _id: 'rsMH4GxtduZZfxQrC' },
{
$addToSet: {
data: {
$each: newData
}
}
}
);
$ push(带$ position)添加到数组的前面:
Collection.update(
{ _id: 'rsMH4GxtduZZfxQrC' },
{
$push: {
data: {
$each: newData,
$position: 0
}
}
}
);
由于从 newData
添加的新对象,文档中的 data
数组将增长 . 那么这种类型的文档更新会导致文档在磁盘上移动吗?
对于这个特定的系统,这些文档中的 data
数组可以增长到75k以上的对象,因此如果在每次$ addToSet或$ push更新后这些文档确实在磁盘上移动,那么文档是否应该用75k空值定义( data: [null,null...null]
)插入,然后可能使用$ set来替换值随着时间的推移?谢谢!
3 回答
它对于用例是可行的,它通常不适用于
$addToSet
和$push
因为它们倾向于通过增长数组来增加文档的大小 .停止 . 你确定你想要不断增长的阵列有成千上万的条目吗?您是否要查询想要的特定条目?你要索引数组条目中的任何字段吗?您可能想重新考虑您的文档结构 . 也许您希望每个
data
条目都是一个单独的文档,每个文件都复制market
,type
,createdAt
等字段?你不会担心文件移动 .为什么阵列会增长到75K?你能为每份文件减少参赛作品吗?这是time series data吗?它对于每个用例都不可行,并且它不是MongoDB表现良好的要求 .
不,这不是真的有用 . 文档大小将根据数组中空值的BSON大小计算,因此当您将
null
替换为另一种类型时,大小将增加,无论如何您将获得文档重写 . 您需要使用所有字段设置为其类型的默认值的对象预分配数组,例如MongoDB使用两种分配策略来存储您的文档,这意味着它将分配文档^ 2的大小进行存储 . 因此,如果您的嵌套数组不会导致总增长大于原始大小为2的幂,则mongo将不必重新分配文档 .
见:http://docs.mongodb.org/manual/core/storage/
这里的底线是,任何“文档增长”几乎总是会导致存储分配的“物理移动”,除非您通过某种方式在原始文档提交上“预先分配” . 是的,有“两个权力”分配,但这并不总是意味着对您的存储案件有效 .
这里的附加"catch"在"capped collections"上,其中"hidden catch"确实是这样的"pre-allocation"方法可能不是副本集中其他成员的"replicated",如果这些指令超出了应用副本集条目的"oplog"期间 .
增长任何超出"initial allocation"分配的结构或可应用的常规技巧 will 会导致该文档在存储空间中超出其最初提供的空间时为"moved" .
为了确保不会发生这种情况,您始终会“预分配”到原始创建的数据的预期条款 . 并且已经描述了这种情况的明显警告 .