MongoDb $elemMatch 与 $lookup 变量
Posted
技术标签:
【中文标题】MongoDb $elemMatch 与 $lookup 变量【英文标题】:MongoDb $elemMatch with $lookup variable 【发布时间】:2021-03-24 11:17:17 【问题描述】:我有一个给定的 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,
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
?或者是否有任何其他优化可用于加速集合查找?
【问题讨论】:
【参考方案1】:首先让我们了解一下为什么您的幼稚方法会失败,Mongo 的 pipelined lookup 文档指出:
$match 阶段需要使用 $expr 运算符来访问变量。 $expr 允许在 $match 语法中使用聚合表达式。
因此,您在 $lookup
开头定义的变量 value
只能通过使用 $expr 访问,现在也在 $expr
文档中指定:
参数可以是任何有效的聚合表达式
遗憾的是,$elemMatch 不是“聚合表达式”,因为它属于“查询语言”。这就是您的第一种方法失败的原因。只是不允许在 $expr
中使用 $elemMatch
,这是访问 $$value
字段所必需的。
那么我们能做些什么呢?好吧,你可以像你已经开始做的那样使用$filter:
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 Playground
【讨论】:
感谢您的详细解释。您的演示结构足以满足我的需求。如果可以的话,我会再为 Mongo Playground 链接 +1!不幸的是,我根据您的解决方案更新的查询比我的第一种方法慢... 没问题,常量值总是最有效的,因为它不需要像$filter
这样的任何结构操作用法。以上是关于MongoDb $elemMatch 与 $lookup 变量的主要内容,如果未能解决你的问题,请参考以下文章
mongodb 中的Multikey Index Bounds解释$elemMatch
带有 elemMatch 的 MongoDB 查询,用于从对象内部匹配嵌套数组数据 [重复]
MongoDB:$ elemMatch和$ and和在数组内查找对象之间有什么区别?