我不确定是真实的的有问题还是缺少文档,您可以将国外收集文档的条件放在查找$match
中,也可以将原始收集文档的条件放在查找$match
中,$expr
。
但是当我想同时使用这两个特性时,它就不起作用了。
{ $lookup:
{
from: 'books',
localField: 'itemId',
foreignField: '_id',
let: { "itemType": "$itemType" },
pipeline: [
{ $match: { $expr: { $eq: ["$$itemType", "book"] } }}
],
as: 'bookData'
}
}
$expr
为原始文档设置了条件。但如果我只想获取带有status: 'OK'
的外来文档,该怎么办?类似于:
{ $match: { status: "OK", $expr: { $eq: ["$$itemType", "book"] } }}
不起作用。
2条答案
按热度按时间wqlqzqxt1#
我试着用你提供的情况来玩。试着把
$expr
作为$match
对象的第一个键。它应该能做到这一点。v6ylcynt2#
目前公认的答案是“错误的”,因为它实际上并没有改变任何东西。
$match
predicate 的字段表示顺序并没有什么区别。我将用您的具体情况来演示这一点,但这里有一个额外的复杂性,我们将在稍后讨论。同时,请考虑以下文档:此查询:
下面这个查询只是颠倒了 predicate 的顺序:
将查找并返回该文档。可以在here和here中找到第一个的演示。
同样,您的原始
$match
:将表现得与已接受答案中的行为相同:
换句话说,是否首先使用
$expr
在行为上没有区别。但是,我怀疑总体聚合没有表达您想要的逻辑。让我们进一步探讨这个问题。首先,我们需要解决这个问题:$expr正在放置原始文档条件
事实并非如此。根据the documentation for
$expr
,该运算符“* 允许在查询语言中使用聚合表达式。*”此功能的主要用途(实际上也是文档中列出的第一个功能)是比较单个文档中的两个字段。在
$lookup
的上下文中,引用原始文档中的字段的功能允许您将它们的值与要联接的集合进行比较。文档中有一些这样的示例,例如此处和该页上引用$expr
其他地方。记住这一点,让我们回到聚合上,如果我理解正确的话,您使用
{ $expr: { $eq: ["$$itemType", "book"] }
predicate 的目的是从 original 集合中过滤文档,对吗?如果是这样的话,那么这不是您当前正在做的聚合。您可以在this playground example中看到,嵌套在
$lookup
pipeline
中的$match
* 不 * 影响原始集合中的文档。相反,您应该通过在基pipeline
上的初始$match
来进行过滤。因此,类似于this的内容:或者,更简单地说,this:
基于所有这些,您的最终管道看起来可能与以下内容类似:
Playground example here。此管道:
1.按数据的
itemType
筛选原始集合(orders
)中的数据。它从示例数据中删除包含_id: 3
的文档,因为该文档的itemType
与我们要查找的文档("book"
)的itemType
不同。1.它使用
localField
/foreignField
语法在books
中查找数据,其中books
文档的_id
与orders
集合中源文档的itemId
相匹配。1.它进一步使用
let
/pipeline
语法来表示books
文档的status
是"OK"
的附加条件。这就是为什么具有"BAD"
的status
的books
文档不会被拉入具有_id: 2
的orders
文档的bookData
中。第二部分和第三部分(合并)的文档位于此处。