我正在考虑使用MongoDB来存储包含键/值对列表的文档。存储它的安全但丑陋和臃肿的方式是
[ ['k1' : 'v1'] , ['k2' : 'v2'], ...]
但是文档元素本质上是在底层BSON数据结构中排序的,所以原则上是:
{k1 : 'v1',
k2 : 'v2', ...}
应该足够了。但是我希望大多数语言绑定会将这些解释为关联数组,因此可能会对排序进行加扰。所以我需要知道的是:
我最感兴趣的是Javascript和PHP,但我也想了解其他语言。感谢任何帮助,或只是链接到一些文档,我可以去RTM。
答案 0 :(得分:11)
从版本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 :(得分:7)
从Mongo 2.6.1开始,它会保持你的字段顺序:
MongoDB在写操作之后保留文档字段的顺序,但以下情况除外:
- _id字段始终是文档中的第一个字段。
- 更新 包括重命名字段名称可能导致重新排序 文件中的字段。
http://docs.mongodb.org/manual/release-notes/2.6/#insert-and-update-improvements
答案 2 :(得分:0)
其中一个难点是在shell中将文档相互比较。
我创建了一个创建自定义mongorc.js的项目,默认情况下会为您打印文档键,因为至少可以看到shell中的内容。如果你想给它一个旋转,它被称为Mongo Hacker。
答案 3 :(得分: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会将此视为副本而不是数组的此对象。