不与 elemMatch 一起使用的多键部分索引
Multikey partial index not used with elemMatch
考虑以下文档格式,它有一个数组字段 tasks
保存嵌入式文档
{
"foo": "bar",
"tasks": [
{
"status": "sleep",
"id": "1"
},
{
"status": "active",
"id": "2"
}
]
}
键 tasks.id
上存在部分索引
{
"v": 2,
"unique": true,
"key": {
"tasks.id": 1
},
"name": "tasks.id_1",
"partialFilterExpression": {
"tasks.id": {
"$exists": true
}
},
"ns": "zardb.quxcollection"
}
以下 $elemMatch
对同一数组元素进行多个条件查询
db.quxcollection.find(
{
"tasks": {
"$elemMatch": {
"id": {
"$eq": "1"
},
"status": {
"$nin": ["active"]
}
}
}
}).explain()
好像没有使用索引
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"tasks": {
"$elemMatch": {
"$and": [{
"id": {
"$eq": "1"
}
},
{
"status": {
"$not": {
"$eq": "active"
}
}
}
]
}
}
},
"direction": "forward"
}
如何让上面的查询使用索引?该索引似乎是通过点符号使用的
db.quxcollection.find({"tasks.id": "1"})
但是我需要相同的数组元素来匹配多个条件,其中包括 status
字段,并且以下内容似乎不等同于上述基于 $elemMatch
的查询
db.quxcollection.find({
"tasks.id": "1",
"tasks.status": { "$nin": ["active"] }
})
部分索引的工作方式是使用路径作为键。使用 $elemMatch,您在查询中没有明确的路径。如果您使用 .explain("allPlansExecution")
检查它,查询计划器甚至不会考虑它。
要从索引中获益,您可以在查询中指定路径:
db.quxcollection.find(
{
"tasks.id": "1",
"tasks": {
"$elemMatch": {
"id": {
"$eq": "1"
},
"status": {
"$nin": ["active"]
}
}
}
}).explain()
它重复了elemMatch条件的一部分,因此索引将用于获取包含特定id任务的所有文档,然后在获取阶段过滤掉具有“活动”任务的文档。我必须承认查询看起来不太好,所以可以在代码中添加一些注释和解释。
考虑以下文档格式,它有一个数组字段 tasks
保存嵌入式文档
{
"foo": "bar",
"tasks": [
{
"status": "sleep",
"id": "1"
},
{
"status": "active",
"id": "2"
}
]
}
键 tasks.id
{
"v": 2,
"unique": true,
"key": {
"tasks.id": 1
},
"name": "tasks.id_1",
"partialFilterExpression": {
"tasks.id": {
"$exists": true
}
},
"ns": "zardb.quxcollection"
}
以下 $elemMatch
对同一数组元素进行多个条件查询
db.quxcollection.find(
{
"tasks": {
"$elemMatch": {
"id": {
"$eq": "1"
},
"status": {
"$nin": ["active"]
}
}
}
}).explain()
好像没有使用索引
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"tasks": {
"$elemMatch": {
"$and": [{
"id": {
"$eq": "1"
}
},
{
"status": {
"$not": {
"$eq": "active"
}
}
}
]
}
}
},
"direction": "forward"
}
如何让上面的查询使用索引?该索引似乎是通过点符号使用的
db.quxcollection.find({"tasks.id": "1"})
但是我需要相同的数组元素来匹配多个条件,其中包括 status
字段,并且以下内容似乎不等同于上述基于 $elemMatch
的查询
db.quxcollection.find({
"tasks.id": "1",
"tasks.status": { "$nin": ["active"] }
})
部分索引的工作方式是使用路径作为键。使用 $elemMatch,您在查询中没有明确的路径。如果您使用 .explain("allPlansExecution")
检查它,查询计划器甚至不会考虑它。
要从索引中获益,您可以在查询中指定路径:
db.quxcollection.find(
{
"tasks.id": "1",
"tasks": {
"$elemMatch": {
"id": {
"$eq": "1"
},
"status": {
"$nin": ["active"]
}
}
}
}).explain()
它重复了elemMatch条件的一部分,因此索引将用于获取包含特定id任务的所有文档,然后在获取阶段过滤掉具有“活动”任务的文档。我必须承认查询看起来不太好,所以可以在代码中添加一些注释和解释。