对一个ObjectId数组而不是单个ObjectId的字段执行$lookup的语法是什么?

订单文件示例:

{
  _id: ObjectId("..."),
  products: [
    ObjectId("..<Car ObjectId>.."),
    ObjectId("..<Bike ObjectId>..")
  ]
}

不工作查询:

db.orders.aggregate([
    {
       $lookup:
         {
           from: "products",
           localField: "products",
           foreignField: "_id",
           as: "productObjects"
         }
    }
])

预期结果

{
  _id: ObjectId("..."),
  products: [
    ObjectId("..<Car ObjectId>.."),
    ObjectId("..<Bike ObjectId>..")
  ],
  productObjects: [
    {<Car Object>},
    {<Bike Object>}
  ],
}

推荐答案

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.

Mongodb相关问答推荐

通过mongoDB中的查找从管道中删除被阻止的用户

如何在MongoDB中正确解析佛年?

除非满足某个条件,否则Mongo是否按日期排序?

根据参考图计算子文档列表的最大值

将数据从一个集合插入另一个集合的聚合

mongoDB文档数组字段中的唯一项如何

从 mongodb Golang 检索时判断零等效时间.时间

Spring Data + MongoDB GridFS 可以通过 Repository 访问吗?

Mongo 删除最后的文件

Ruby on Rails 的 Cassandra、mongodb 或 couchdb

使用绝对类型在 Typescript 中编写 Mongoose 的类型化模型和模式的类和接口

如何在 MongoDb 中使用杰克逊将日期字段存储为 ISODate()

如何在 MongoDB 中进行内部连接?

$lookup 结果 mongodb 的计数

如何在 Ruby on Rails 环境中使用 Mongoid 进行通配符搜索?

适用于 Windows 10 64 位的 MongoDB 下载

如果我在 MongoDB 上使用 LINQ,为什么会失go 性能?

MEAN 堆栈文件上传

Cannot connect to MongoDB errno:61

MongoDB Compass 中 JSON 输入意外结束