2017年更新
$lookup 现在可以直接使用数组作为本地字段. $unwind
不再需要。
旧答案
The $lookup聚合管道阶段不能直接与数组一起工作。设计的主要目的是将“左连接”作为可能的相关数据的“一对多”类型的连接(或者实际上是“查找”)。但该值应该是单数而不是数组。
因此,在执行之前,您必须先对内容进行“去规范化”$lookup
操作才能使其发挥作用。这意味着使用$unwind:
db.orders.aggregate([
// Unwind the source
{ "$unwind": "$products" },
// Do the lookup matching
{ "$lookup": {
"from": "products",
"localField": "products",
"foreignField": "_id",
"as": "productObjects"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$productObjects" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"productObjects": { "$push": "$productObjects" }
}}
])
After $lookup
匹配每个数组成员,结果是一个数组本身,所以你$unwind
再次和$group to $push最终结果的新数组。
请注意,任何未找到的“左连接”匹配都将为给定产品上的“productObjects”创建一个空数组,从而在第二个匹配时否定“product”元素的文档。$unwind
叫做。
虽然直接应用于数组会很好,但目前的工作方式只是将一个奇异值与可能的多个值进行匹配。
As $lookup
基本上是非常新的,目前它的工作原理对于那些熟悉的人来说是熟悉的mongoose作为“穷人版”.populate()
那里提供的方法。区别在于$lookup
提供“连接”的“服务器端”处理,而不是在客户端上,并且其中的一些“成熟度”$lookup
目前还缺少什么.populate()
提供(例如直接在数组上插入查找)。
这实际上是一个需要改进的分配问题服务器-22881,所以如果幸运的话,这将在下一个版本或不久之后发布。
作为设计原则,您当前的结构既不好也不坏,只是在创建任何“连接”时受到开销。因此,MongoDB 一开始的基本原则就适用,如果您“可以”接受在一个集合中“预连接”的数据,那么最好这样做。
另一件可以说的事$lookup
作为一般原则,此处“连接”的目的是按与此处所示相反的方式工作。因此,最好的一般原则是“相关文档”包含对“父”文档的引用,而不是将其他文档的“相关 ID”保留在“父”文档中。
So $lookup
可以说通过“关系设计”“工作得最好”,这与猫鼬这样的东西相反.populate()
执行它的客户端连接。通过识别每个“许多”中的“一个”,然后您只需拉入相关项目,而无需$unwind
首先是数组。