MongoDB查询使用嵌入式文档作为关键

Ral*_*alf 5 mongodb

精简版:

如果我有索引{"category": 1}和文档{"category": {type: "memory", class: "DDR400"},我该如何进行查询,例如{"category.type": "memory"}使用我的索引?

长版:

使用MongoDB,我想使用嵌入式文档作为索引的键.

例如,我可能有一些这样的文档(对于假设的产品数据库):

{"category": {"type": "hard-drive", "form_factor": "2.5in", "size": "500GB"}, ...}
{"category": {"type": "hard-drive", "form_factor": "3.5in", ...}, ...}
{"category": {"type": "memory", "class": "DDR400", ...}, ...}
Run Code Online (Sandbox Code Playgroud)

对于上面的示例,我可能想要执行以下查询:

{"category.type": "hard-drive"}
{"category.type": "hard-drive", "category.form_factor": "2.5in"}
{"category.type": "memory"}
{"category.type": "memory", "category.class": "DDR400"}
Run Code Online (Sandbox Code Playgroud)

我的问题是创建一个索引.http://www.mongodb.org/display/DOCS/Indexes#Indexes-DocumentsasKeys上的文档描述了两个选项:

例如,第一个选项是创建复合索引{ "category.type": 1, "category.class": 1 }.这对我的情况不适用,因为我可能有许多不同类型的子类别.

第二种选择是使用文档作为关键:{ "category": 1 }.现在一个查询,如{"category": {"type": "memory", "class": "DDR400"}}将使用索引,但{"category": {"type": "memory"}}不会返回任何内容,{"category.type": "memory"}也不会使用索引.有没有办法使用这个索引进行查询,结果如下{"category.type": "memory"}

我怀疑使用类似{"category" {"$gt": ..., "$lt": ...}应该工作的查询,但是我应该在那里放入什么空白?

Thi*_*ilo 3

category.type为(可能除了)创建一个单独的索引category似乎是最好的选择。

$gt您可以使用和进行范围查询$lt。这些将适用于嵌入对象的二进制表示,它仅适用于第一个(按存储顺序)字段,并且仅当第一个字段在所有文档中都相同时才有效,因此它不是很灵活,并且容易破坏。

   {"category"  : {"$gt": {"type": "memory"},  "$lt": {"type": "memoryX" } } }
Run Code Online (Sandbox Code Playgroud)

这里的“内存X”作为一个分界点:所有带有“内存”的东西都会在此之前排序。

请注意,这要求“类型”字段是所有具有该字段的文档的二进制表示形式中的第一个字段。它也仅适用于“type”字段(无法查询第一个位置的其他字段,您必须预先选择一个),因此与专用的“category.type”索引(只是空格)相比,您实际上没有任何优势节省)。

我之前尝试过这个想法,请参阅邮件列表上的这个帖子。它确实有效,但你必须小心你在做什么:

它既受支持又稳定。许多分片/复制内部使用嵌入文档的 _id 值。

这里唯一需要注意的是嵌入元素中键的顺序。它们按二进制表示形式排序,因此 {x:1, y:1} 与 {y:1, x:1} 不同,并且排序方式也不同。它们不仅排序不同,而且值也不同。默认情况下,某些语言总是对字典/哈希/映射中的键进行排序。

再次考虑在您需要的字段上创建额外的索引。

就我而言,我只需要查询“a”,“a,b”或“a,b,c”,或“a,x,y”,其中包含x的文档从不包含“b”或“ C'

那时这可能会起作用。不过,我仍然会做两个复合索引a,ba,x。或者也许只是bx。鉴于文档包含bx,您可能已经有效地过滤掉了不相关的文档a( form_factor = 2.5in 已经告诉您它是硬盘, class = DDR400 已经使其成为内存)。经过筛选后a,b,您可能不需要索引来进一步深入c

通过对二进制表示使用这个棘手的查询,您将依赖于所谓的实现细节。您可能会遇到喜欢重新排序字段的驱动程序,或者类似Mongo 本身有时会重新排列内容的问题