首页 文章

MongoDB:如果使用$ addToSet或$ push,您是否应该预先分配文档?

提问于
浏览
1

我一直在研究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 回答

  • 1

    我理解强烈建议文档结构在插入点完全构建(预分配),这样未来对该文档的更改不需要在磁盘上移动文档 . 这在使用$ addToSet或$ push时是否适用?

    它对于用例是可行的,它通常不适用于 $addToSet$push 因为它们倾向于通过增长数组来增加文档的大小 .

    这些文档中的数据数组可以增长到75k以上的对象

    停止 . 你确定你想要不断增长的阵列有成千上万的条目吗?您是否要查询想要的特定条目?你要索引数组条目中的任何字段吗?您可能想重新考虑您的文档结构 . 也许您希望每个 data 条目都是一个单独的文档,每个文件都复制 markettypecreatedAt 等字段?你不会担心文件移动 .

    为什么阵列会增长到75K?你能为每份文件减少参赛作品吗?这是time series data吗?它对于每个用例都不可行,并且它不是MongoDB表现良好的要求 .

    应该在插入时使用75k nulls(data:[null,null ... null])定义文档,然后使用$ set来替换值随着时间的推移?

    不,这不是真的有用 . 文档大小将根据数组中空值的BSON大小计算,因此当您将 null 替换为另一种类型时,大小将增加,无论如何您将获得文档重写 . 您需要使用所有字段设置为其类型的默认值的对象预分配数组,例如

    {
        "date" : ISODate("1970-01-01T00:00:00Z")    // use a date type instead of a string date
        "price" : 0,
        "amount" : 0,
        "tid" : "000000", // assuming 7 character code - strings icky for default preallocation
        "type" : "none"    // assuming it's "buy" or "sell", want a default as long as longest real values
    }
    
  • 2

    MongoDB使用两种分配策略来存储您的文档,这意味着它将分配文档^ 2的大小进行存储 . 因此,如果您的嵌套数组不会导致总增长大于原始大小为2的幂,则mongo将不必重新分配文档 .

    见:http://docs.mongodb.org/manual/core/storage/

  • 1

    这里的底线是,任何“文档增长”几乎总是会导致存储分配的“物理移动”,除非您通过某种方式在原始文档提交上“预先分配” . 是的,有“两个权力”分配,但这并不总是意味着对您的存储案件有效 .

    这里的附加"catch"在"capped collections"上,其中"hidden catch"确实是这样的"pre-allocation"方法可能不是副本集中其他成员的"replicated",如果这些指令超出了应用副本集条目的"oplog"期间 .

    增长任何超出"initial allocation"分配的结构或可应用的常规技巧 will 会导致该文档在存储空间中超出其最初提供的空间时为"moved" .

    为了确保不会发生这种情况,您始终会“预分配”到原始创建的数据的预期条款 . 并且已经描述了这种情况的明显警告 .

相关问题