【问题标题】:Can MongoDB and its drivers preserve the ordering of document elementsMongoDB 及其驱动程序能否保留文档元素的顺序
【发布时间】:2012-01-24 11:56:45
【问题描述】:

我正在考虑使用 MongoDB 来存储包含键/值对列表的文档。存储它的安全但丑陋和臃肿的方式是

[ ['k1' : 'v1'] , ['k2' : 'v2'],  ...]

但是文档元素在底层 BSON 数据结构中固有地是有序的,所以原则上:

{k1 : 'v1', 
 k2 : 'v2',  ...}

应该够了。但是我希望大多数语言绑定会将这些解释为关联数组,因此可能会打乱顺序。所以我需要知道的是:

  • MongoDB 本身是否承诺保留第二种形式的项目排序。
  • 语言绑定是否有一些 API 可以提取有序形式 - 即使通常的“方便”API 返回关联数组。

我在这里主要对 Javascript 和 PHP 感兴趣,但我也想了解其他语言。感谢您提供任何帮助,或者只是指向我可以使用 RTM 的一些文档的链接。

【问题讨论】:

  • mongodb用户论坛是最好的问这些问题的地方; mongodb 开发人员在回答此类问题方面非常有帮助,并且能够为您提供权威的答案。 groups.google.com/forum/#!forum/mongodb-user
  • @JasonS 谢谢。我在这里问的一个原因是这个问题涉及太多不同的语言/标准,我不知道该去哪里找。但你是对的,Mongo 位于它们的中心。
  • 这个地方其实问比较合适。
  • 这就是答案。

标签: php javascript json mongodb bson


【解决方案1】:

从版本 2.6 开始,MongoDB preserves the order of fields where possible. 但是,_id 字段始终排在第一位,重命名字段可能导致重新排序。但是,我通常会尽量不要依赖这样的细节。正如最初的问题所提到的,还有额外的层需要考虑,每个层都必须为订单的稳定性提供某种保证......

原答案:

不,MongoDB does not make guarantees about the ordering of fields:

“不保证字段顺序在更新后会保持一致或相同。”

特别是,更改文档大小的就地更新通常会更改字段的顺序。例如,如果您 $set 一个字段的旧值为 number 类型,而新值为 NumberLong,则字段通常会重新排序。

但是,数组保持正确的顺序:

[ {'key1' : 'value1'}, {'key2' : 'value2'}, ... ]

我根本不明白为什么这是“丑陋”和“臃肿”。存储复杂对象的列表再简单不过了。但是,将对象滥用为列表绝对是丑陋的:对象具有关联数组语义(即,给定名称只能有一个字段),而列表/数组则没有:

// not ok:
db.foo2.insert({"foo" : "bar", "foo" : "lala" });
db.foo2.find();
{ "_id" : ObjectId("4ef09cd9b37bc3cdb0e7fb26"), "foo" : "lala" }

// a list can do that
db.foo2.insert({ 'array' : [ {'foo' : 'bar'}, { 'foo' : 'lala' } ]});
db.foo2.find();
{ "_id" : ObjectId("4ef09e01b37bc3cdb0e7fb27"), "array" : 
      [ { "foo" : "bar" }, { "foo" : "lala" } ] }

请记住,MongoDB 是一个对象数据库,而不是键/值存储。

【讨论】:

  • 干净...没有更多可添加的...+1
  • 好吧,我会那样做的。我仍然说它很丑,但 MongoDB 以这种方式工作是很合理的。 “对象具有关联数组语义”是一种 javascript 主义(通常我不会将对象一词用于此类数据结构)。从我对 MongoDB 的(肤浅的)阅读来看,我认为它是一个 BSON 文档数据库——而且 BSON 有一个非常清晰的规范,其中元素是有序的。相反,MongoDB 是类似 Javascript 的对象(或类似 python 的字典)的存储,它恰好在引擎盖下使用 BSON。很公平。
  • “MongoDB 不保证字段的顺序”是错误的。 MongoDB 确实对字段的顺序做出了某些严格的保证。它不保证在每次操作之后(例如“更新后”),但它肯定会做出保证。也就是说,根据字典保留顺序是一场噩梦,几乎总是最好避免,因为大多数语言的本地字典都不会。
  • 我可以看出这句话并不完全正确,因为如果您愿意,每个确定性系统都会做出保证。但我发现它几乎不值得投反对票。注意详细说明这些保证是什么,它们记录在哪里(源代码除外,但我们不想依赖实现细节)以及如何在单点代码具有的实际环境中使用它们很少有机会知道对数据执行了哪些操作?
  • 这个答案在 2017 年似乎已经过时了
【解决方案2】:

其中一个痛点是在 shell 中比较文档。

我创建了一个项目,该项目创建了一个自定义的 mongorc.js,它在打印出文档键时默认为您排序,因此至少您可以清楚地看到 shell 中发生了什么。如果你想试一试,它被称为Mongo Hacker

【讨论】:

    【解决方案3】:

    从 Mongo 2.6.1 开始,它确实保持了字段的顺序:

    MongoDB 保留写入操作后文档字段的顺序,但以下情况除外:

    • _id 字段始终是文档中的第一个字段。
    • 更新 包括重命名字段名称可能会导致重新排序 文档中的字段。

    http://docs.mongodb.org/manual/release-notes/2.6/#insert-and-update-improvements

    【讨论】:

      【解决方案4】:

      尽管从 Mongo 2.6.1 开始,它确实保留了顺序,但仍应小心更新操作。

      mattwad 指出更新可以重新排序,但至少还有一个我能想到的其他问题。

      例如 $addToSet:

      https://docs.mongodb.com/manual/reference/operator/update/addToSet/

      $addToSet 用于数组中的嵌入文档时在此处讨论/举例说明: https://stackoverflow.com/a/21578556/3643190

      在帖子中,mnemosyn 解释了 $addToSet 在逐个值比较的深层匹配元素时如何忽略顺序。

      ($addToSet 仅在记录唯一时添加)

      如果一个人决定像这样构造数据,这是相关的:

      [{key1: v1, key2: v2}, {key1: v3, key2: v4}]
      

      有了这样的更新(注意嵌入文档的不同顺序):

      db.collection.update({_id: "id"},{$addToSet: {field:
      {key2: v2, key1: v1}
      }});
      

      Mongo 会将其视为重复的,而不是数组中的此对象。

      【讨论】:

        猜你喜欢
        • 2022-01-08
        • 2010-11-29
        • 1970-01-01
        • 2011-10-28
        • 2011-11-05
        • 1970-01-01
        相关资源
        最近更新 更多