2017 update
$lookup can now directly use an array as the local field.$unwind
不再需要了.
Old answer
$lookup
聚合管道阶段不会直接与数组一起工作.设计的主要目的是对可能的相关数据进行"左连接",作为"一对多"类型的连接(或者实际上是"查找").但该值是单数的,而不是array.
因此,在执行$lookup
操作之前,必须先对内容进行"go 正常化",才能使其正常工作.这意味着使用$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" }
}}
])
在$lookup
匹配每个数组成员后,结果就是一个数组本身,因此再次$unwind
和$group
到$push
个新数组才能得到最终结果.
请注意,任何未找到的"左连接"匹配项都将为给定产品上的"productObjects"创建一个空数组,从而在调用第二个$unwind
时否定"product"元素的文档.
虽然直接应用到数组会很好,但它只是通过将一个单数值与一个可能的多匹配来实现的.
由于$lookup
基本上是非常新的,所以它目前的工作原理与那些熟悉mongoose的人所熟悉的一样,mongoose是.populate()
方法的"穷人版".不同之处在于$lookup
提供了"连接"的"服务器端"处理,而不是在客户端,而且$lookup
中的一些"成熟度"目前与.populate()
提供的"成熟度"不同(例如直接在数组中插入查找).
这实际上是"改进SERVER-22881"的一个指定问题,所以如果运气好的话,它将在下一个版本或之后不久发布.
作为一个设计原则,您当前的 struct 既不好也不坏,只是在创建任何"连接"时会受到开销的影响.因此,MongoDB在《盗梦空间》中的基本原则是适用的,如果你"可以"在一个集合中"预先加入"数据,那么最好这样做.
另一件事可以说$lookup
是一个普遍的原则,这里"连接"的意图是以与这里所示相反的方式工作.因此,与其将其他文档的"相关ID"保存在"父"文档中,最好的一般原则是"相关文档"包含对"父"的引用.
因此,$lookup
可以说是"最佳工作",其"关系设计"与mongoose .populate()
的客户端连接相反.相反,通过在每个"多"中标识"一",您只需输入相关项,而无需首先输入array.