mongodb - $lookup 查找数组中的 ObjectId

对作为 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 年更新

$lookup can now directly use an array as the local field . $unwind 不再需要。

旧答案

$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" }
    }}
])

$lookup 匹配每个数组成员后,结果就是一个数组本身,所以你再次$unwind$group$push最终结果的新数组。

请注意,任何未找到的“左连接”匹配项将为给定产品上的“productObjects”创建一个空数组,从而在第二个 $unwind 被调用。

虽然直接应用到数组会很好,但目前这就是通过将奇异值与可能的多个匹配来实现的。

由于 $lookup 基本上是非常新的,它目前的工作方式与熟悉 mongoose 的人一样。作为那里提供的 .populate() 方法的“可怜的版本”。区别在于 $lookup 提供“连接”的“服务器端”处理,而不是在客户端上,并且 $lookup 中的一些“成熟度”目前是缺少 .populate() 提供的功能(例如直接在数组上插入查找)。

这实际上是一个指定的改进问题 SERVER-22881 ,所以运气好的话,它会在下一个版本或不久之后发布。

作为设计原则,您当前的结构既不好也不坏,只是在创建任何“连接”时会产生开销。因此,MongoDB 在初始阶段的基本原则适用,如果您“可以”使用“预先加入”的数据在一个集合中,那么最好这样做。

另一件事可以说是 $lookup 作为一般原则,这里“加入”的意图是与这里显示的相反。因此,与其将其他文档的“相关 ID”保留在“父”文档中,最佳的一般原则是“相关文档”包含对“父”的引用。

所以 $lookup 可以说是“工作最好”的“关系设计”,这与 mongoose .populate() 之类的东西如何执行它的客户端相反侧连接。通过在每个“多”中标识“一”,您只需拉入相关项目,而无需先 $unwind 数组。

https://stackoverflow.com/questions/34967482/

相关文章:

mongodb - 无法验证到 mongo, "auth fails"

mongodb - 如何使用 MongoDB 过滤子文档中的数组

java - Spring Data 的 MongoTemplate 和 MongoReposito

javascript - node.js mongodb 通过_id node-mongodb-na

mongodb - 无法启动/启动本地 mongo db

mongodb - 如何将 mongodb 客户端连接到本地 Meteor MongoDB

macos - mac上mongodb数据库的位置

MongoDB select count(distinct x) on an indexed col

node.js - 如何在 mongodb-native findOne() 中使用变量作为字段名?

sql - mongo中的外键?