以以下数据为例:
{
_id: 1,
item: "abc",
stock: [
{ size: "S", color: "red", quantity: 25 },
{ size: "S", color: "blue", quantity: 10 },
{ size: "M", color: "blue", quantity: 50 }
]
}
{
_id: 2,
item: "def",
stock: [
{ size: "S", color: "blue", quantity: 20 },
{ size: "M", color: "blue", quantity: 5 },
{ size: "M", color: "black", quantity: 10 },
{ size: "L", color: "red", quantity: 2 }
]
}
{
_id: 3,
item: "ijk",
stock: [
{ size: "M", color: "blue", quantity: 15 },
{ size: "L", color: "blue", quantity: 100 },
{ size: "L", color: "red", quantity: 25 }
]
}
说我要过滤掉符合条件stock
的{{1}}。我已经在size = 'L'
字段上有了一个多键索引。
在聚合管道中,如果我使用以下两个操作:
stock.size
我会得到理想的结果,但是当数据库很大时,[{$unwind: {path: "$stock"}},
{$match: {"stock.size": "L"}}]
步骤将不得不扫描整个集合,而无需利用现有索引,这是非常低效的。
如果我颠倒$unwind
和$unwind
操作的顺序,$match
将利用索引来应用早期过滤,但最终结果将不是所希望的:它将获取额外的$match
,这些stock
的大小不是L,但是具有同级stock
的L大小的同级item
。
我是否必须使用相同的$match
操作两次,即在$unwind
之前和之后都要使用索引并返回正确的结果?
答案 0 :(得分:2)
是的,您可以在聚合管道中两次使用$match
阶段,但是这里只有第一个$match
阶段将使用索引,第二个阶段将使用collscan。
[
{ "$match": { "stock.size": "L" }},
{ "$unwind": { "path": "$stock" }},
{ "$match": { "stock.size": "L" }}
]
[
{ "$match": { "stock.size": "L" } },
{ "$addFields": {
"stock": {
"$filter": {
"input": "$stock",
"as": "st",
"cond": { "$eq": ["$stock.size", "L"] }
}
}
}}
]