13

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

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

但是文档元素在底层 BSON 数据结构中本质上是有序的,因此原则上:

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

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

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

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

4

4 回答 4

12

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

原答案:

不,MongoDB不保证字段的顺序

“无法保证更新后的现场顺序将保持一致或相同。”

特别是,改变文档大小的就地更新通常会改变字段的顺序。例如,如果您$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 是一个对象数据库,而不是键/值存储。

于 2011-12-20T14:40:50.020 回答
9

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

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

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

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

于 2014-05-14T14:39:39.323 回答
0

这样做的痛点之一是在 shell 中将文档相互比较。

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

于 2014-03-13T22:49:07.047 回答
0

尽管从 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 将把它看作是重复的,而不是数组中的这个对象。

于 2017-01-30T18:35:13.817 回答