简短版:
如果我有索引{"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", ...}, ...}
对于上面的示例,我可能想要执行以下查询:
{"category.type": "hard-drive"}
{"category.type": "hard-drive", "category.form_factor": "2.5in"}
{"category.type": "memory"}
{"category.type": "memory", "category.class": "DDR400"}
我的问题是创建一个索引。 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": ...}
之类的查询应该有效,但是我应该在那里添加空格?
答案 0 :(得分:3)
为category.type
创建单独的索引(可能除category
之外)似乎是最佳选择。
您可以使用$gt
和$lt
的范围查询。那些将用于嵌入对象的二进制表示,它仅适用于第一个(在存储顺序中)字段,并且仅当第一个字段在所有文档中相同时,因此它不是非常灵活且易于破解。
{"category" : {"$gt": {"type": "memory"}, "$lt": {"type": "memoryX" } } }
“memoryX”在这里作为一个截止点:所有带有“记忆”的东西都会在此之前排序。
请注意,这要求“type”字段是包含所有文档的二进制表示形式中的第一个字段。它也仅适用于“类型”字段(无法在第一个位置查询其他字段,您必须先选择一个),因此实际上没有优于专用“category.type”索引(只是空格)储蓄)。
我之前正在尝试这个想法,请参阅this thread on the mailing list。它确实有效,但你必须小心你正在做的事情:
它既支持又稳定。许多分片/复制 内部使用嵌入式文档的_id值。
这里唯一要注意的是键的排序 嵌入元素。它们按二进制表示排序 {x:1,y:1}与{y:1,x:1}不同,并且排序方式不同。不 只是它们的排序方式不同,它们的价值也不同。一些 语言总是默认对字典/散列/映射中的键进行排序。
再次考虑在您需要的字段上创建额外的索引。
那可能会有用。不过,我仍然会做两个复合索引在我的情况下,我只需要查询'a','a,b'或'a,b,c'或'a,x,y',其中包含x的文档从不包含'b '或'c'
a,b
和a,x
。或者只是b
和x
。鉴于文档包含b
或x
,您可能已经有效地过滤掉了与a
无关的文档(form_factor = 2.5in已经告诉您它是硬盘,类= DDR400已经使它成为内存)。
在按a,b
过滤后,您可能不需要索引在c
上进一步向下钻取。
通过对二进制表示使用这个棘手的查询,您将自己依赖于可称为实现细节的内容。您可能会受到喜欢重新排序字段的驱动程序的攻击,或者像this issue这样的关于Mongo本身有时重新排序的事情。
答案 1 :(得分:2)
如果您正在为每个“类型”搜索一个基本属性,那么只需添加一个单独的字段,并创建一个复合索引,例如:
{"category": {"type": "hard-drive", "form_factor": "2.5in", "searchfield: "2.5in", ...}, ...}
{"category": {"type": "memory", "class": "DDR400", searchfield: "DDR400", ...}, ...}
如果您要搜索多个字段,但这些字段的值不同,则可以将这些值添加为标记,然后再创建一个复合键:
{"category": {"type": "hard-drive", "form_factor": "2.5in", "size": "500GB", "tags": ["2.5in", "500GB"]}, ...}
{"category": {"type": "memory", "class": "DDR400", "tags": ["DDR400"], ...}, ...}