MongoDb$elemMatch和$lookup变量
我有一个给定的MongoDb集合,其中的文档与以下内容类似:MongoDb$elemMatch和$lookup变量,mongodb,query-optimization,Mongodb,Query Optimization,我有一个给定的MongoDb集合,其中的文档与以下内容类似: { items: [ { id: 1, data: 'a' }, { id: 2, data: 'b' }, { id: 3, data: 'c' }, ] } 现在我必须从这个集合中$lookup。我需要id=2的元素中的数组数据,其中id=1的数据与查找值$$value匹配。我第一次天真地尝试找到正确的文档如下所示: $match { items: { $elemMatch: { id: 1, d
{
items: [
{ id: 1, data: 'a' },
{ id: 2, data: 'b' },
{ id: 3, data: 'c' },
]
}
现在我必须从这个集合中$lookup
。我需要id=2的元素中的数组数据,其中id=1的数据与查找值$$value
匹配。我第一次天真地尝试找到正确的文档如下所示:
$match {
items: { $elemMatch: {
id: 1,
data: '$$value'
} }
}
但是,$$value
不会被计算,因此数据将与文本而不是其值进行比较。我还尝试使用$expr
计算该值,但无法获得正确的语法(如果可能的话)
我能够开始工作的唯一工作方式是先提取数据,然后进行匹配:
[
{
$project: {
_id: 0,
data1: {
$filter: {
input: '$items', as: 'item',
cond: {$eq: ['$$item.id', 1]}
}
},
data2: {
$filter: {
input: '$items', as: 'item',
cond: {$eq: ['$$item.id', 2]}
}
},
}
},
{
$set: {
data1: {$arrayElemAt: ['$data1.data', 0]},
data2: {$arrayElemAt: ['$data2.data', 0]}
}
},
{
$match: {
$expr: {$eq: ['$data1', '$$value']}
}
}
];
但正如人们所料,这种方法要慢得多。对于所涉及的数据,查询耗时7秒,而上层方法(使用常量而不是变量$$value
)的速度则快了3倍
是否可以在
$elemMatch
运算符中直接使用变量$$value
?或者是否有任何其他优化可用于加快集合查找?因此,首先让我们了解为什么您的天真方法失败,Mongo的文档指定:
$match阶段需要使用$expr运算符来访问变量$expr允许在$match语法中使用聚合表达式
因此,您在$lookup
开头定义的变量值
只能通过使用来访问,现在也在$expr
文档中指定:
参数可以是任何有效的聚合表达式
遗憾的是,它不是一个“聚合表达式”,因为它属于“查询语言”。这就是为什么你的第一个方法失败了。您不允许在访问$$value
字段所需的$expr
中使用$elemMatch
那么我们能做什么呢?好吧,你可以像你已经开始做的那样使用:
db.collection.aggregate([
{
$lookup: {
from: "collection2",
let: {
value: "$data"
},
pipeline: [
{
$match: {
$expr: {
$gt: [
{
$size: {
$filter: {
input: "$items",
as: "item",
cond: {
$and: [
{
$eq: [
"$$item.id",
1
]
},
{
$eq: [
"$$item.data",
"$$value"
]
}
]
}
}
}
},
0
],
}
}
}
],
as: "res"
}
}
])
如果您提供集合的完整结构和所需的最终结果,那么完整的回答就更容易了,因为为了编写这个管道,我不得不在这里猜测一些内容
谢谢您的详细解释。你的演示结构足以满足我的需要。如果可以,我会给Mongo游乐场链接另一个+1!不幸的是,我基于您的解决方案更新的查询比我的第一种方法慢…没问题,常量值总是最有效的,因为它不需要任何结构操作使用,如
$filter
。