我在为查询创建索引时遇到问题,但在网络上找不到任何类似的解决方案,所以也许有些人会帮助我。
为了简化问题,我们假设我们的手机有一些属性,
{
"type":"Samsung",
"model":"S3",
"attributes":[{
"value":"100",
"name":"BatteryLife"
},{
"value":"200$",
"name":"Price"
}
}
使用index:{“type”:1,“attributes.value”:1}
我们每种类型都有数百万部手机,我想找到具有属性的给定类型的手机,我的查询如下:
db.Phone.aggregate([
{ "$match" : { "type" : "Samsung"}} ,
{ "$match" : { "attributes" : { "$all" : [
{ "value" : "100", "name" : "BatteryLife" } ,
{ "value" : "200$", "name" : "Price"}
]}
}
}
])
它有效! 问题是这个查询非常低效,因为它只使用我的索引的第一部分,即“类型”(我有各种类型的数百万部电话),并且不使用'attributes.value'部分(类型) + attributes.value几乎是唯一的,因此它会显着降低复杂性。)
@Edit 感谢Neil Lunn我知道这是因为索引仅在我的第一场比赛中使用,所以我必须更改我的查询。
@ EDIT2 我想我找到了解决方案:
db.Phone.aggregate([
{$match: {
$and: [
{type: "Samsung"},
{attributes: {
$all: [
{ "value":"100", "type" : "BatteryLife" },
{ "value":"200$", "type" : "Price" }
]
}}
]}
}])
+ db.Phone.ensureIndex({type:1,attributes:1})似乎有效。我想我们现在可以关闭了。感谢关于$ match的提示。
答案 0 :(得分:0)
要充分利用索引,您需要在使用索引中所有字段的管道中尽早获得$ match。并且避免使用$and
运算符,因为它是不必要的,并且在当前(2.4)版本中可能导致索引无法被充分利用(幸运地为即将到来的2.6修复)。
但是,查询不太正确,因为您需要使用$elemMatch
来确保使用相同的元素来满足名称和值字段。
您的查询应该是:
db.Phone.aggregate([
{$match: { type: "Samsung",
attributes: { $all: [
{$elemMatch: {"value":"100", "type" : "BatteryLife" }},
{$elemMatch: {"value":"200$", "type" : "Price" }}
] }
}
}]);
现在,它的不是将成为一个被覆盖的查询,因为嵌入了attributes.value和name,更不用说名称不在索引中了。
您需要索引为{"type":1, "attributes.value":1, "attributes.name":1}
以获得最佳效果,但仍然无法覆盖,它会比现在更具选择性。