Mongo中对象数组和对象的索引优化对比

37

我正在实现一个联系人数据库,其中有相当多的字段需要处理。其中大部分是预定义的,可以考虑为绑定字段,但还有一些不是。我们将其中一个称为“群组”。我们目前的实现方式是(每个文档/联系人都有“群组”字段):

'groups' : {
   152 : 'hi',
   111 : 'group2'
}

但经过一些阅读后,似乎我应该这样做:

'groups' : [
   { 'id' : 152, 'name' : 'hi' },
   { 'id' : 111, 'name' : 'group2' }
   ...
]

然后应用索引db.contact.ensureIndex({'groups.id':1});

我的问题与功能有关。这两种结构之间的区别是什么?索引实际上是如何构建的(它只是在每个文档/联系人内进行索引还是构建一个包含所有文档/联系人中所有组的大规模索引)。

我认为这在结构上是最佳方式,但如果我错了,请告诉我。

1个回答

62
查询在第二种情况下会更容易,其中“groups”是子文档的数组,每个子文档都有一个“id”和一个“name”。Mongo不支持“通配符”查询,因此如果您的文档以第一种方式结构化,并且想要查找具有值“hi”的子文档,但不知道键是152,您将无法做到。使用第二个文档结构,您可以轻松查询{"groups.name":"hi"}。有关查询嵌入式对象的更多信息,请参阅标题为“点表示法(进入对象)”的文档http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29。“高级查询”文档中的“数组中的值”和“嵌入对象中的值”部分也很有用:http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray
对于 {'groups.id':1} 的索引,将为每个文档中每个“groups”数组中的“id”键创建一个索引条目。对于“groups”的索引,每个文档只会创建一个索引条目。
如果您有第二种类型的文档,并且具有“groups”的索引,则必须匹配整个子文档才能利用索引进行查询。例如,给定以下文档:
{ "_id" : 1, "groups" : [ { "id" : 152, "name" : "hi" }, { "id" : 111, "name" : "group2" } ] }

查询

db.<collectionName>.find({groups:{ "id" : 152, "name" : "hi" }}) 

将利用索引,但查询
db.<collectionName>.find({"groups":{$elemMatch:{name:"hi"}}})

或者

db.<collectionName>.find({"groups.name":"hi"})

不会。

您创建的索引应该取决于您最常执行的查询。

您可以使用.explain()命令尝试使用哪个(如果有)索引来执行查询。 http://www.mongodb.org/display/DOCS/Explain第一行“cursor”将告诉您正在使用哪个索引。“cursor”:“BasicCursor”表示正在执行完整的集合扫描。

文档中有关索引的更多信息:http://www.mongodb.org/display/DOCS/Indexes

上述“索引数组元素”部分链接到名为“Multikeys”的文档: http://www.mongodb.org/display/DOCS/Multikeys

希望这将提高您对如何在嵌入式文档上进行查询以及如何使用索引的理解。 如果您有任何后续问题,请告诉我们!


1
这是一个很好的答案,但前两个链接已经失效了。我一直在搜索,但无法在网络上找到它们的新位置。有什么帮助吗? - benathon
嗨,通过阅读您的回复,我在想是否索引将用于像 db.<collectionName>.find({"groups":{$elemMatch:{"id":152}}}) 这样的查询? - Sebastien Lorber
2
@portforwardpodcast 第一个链接似乎是 https://docs.mongodb.com/manual/core/document/#dot-notation - Kanembel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接