MongoDB $lookup 和 $map 对象数组

标签 mongodb mongodb-query aggregation

我试图这样做几天,但找不到任何成功
我正在使用 MongoDB,我尝试使用许多管道步骤来完成它,但找不到方法。
我有一个玩家集合,每个玩家包含一个 items 数组

{
    "_id": ObjectId("5fba17c1c4566e57fafdcd7e"),
    "username": "moshe",
    "items": [
        {
            "_id": ObjectId("5fbb5ac178045a985690b5fd"),
            "equipped": false,
            "itemId": "5fbb5ab778045a985690b5fc"
        }
    ]
}
我有一个项目集合,其中有关于每个项目的更多信息
在播放器 items 数组中。
{
    "_id": ObjectId("5fbb5ab778045a985690b5fc"),
    "name": "Axe",
    "damage": 4,
    "defense": 6
}
我的目标是拥有一个玩家文档,其中包含有关 items 数组中项目的所有信息,因此它看起来像这样:
{
    "_id": ObjectId("5fba17c1c4566e57fafdcd7e"),
    "username": "moshe",
    "items": [
        {
            "_id": ObjectId("5fbb5ac178045a985690b5fd"),
            "equipped": false,
            "itemId": "5fbb5ab778045a985690b5fc",
            "name": "Axe",
            "damage": 4,
            "defense": 6
        }
    ]
}

最佳答案

  • $unwind解构 items阵列
  • $lookup加入items收藏、传递itemsId使用 $toObjectId 将其转换为对象 ID 后进入 let并通过 items目的,
  • $match itemId条件
  • $mergeObject合并 items对象和 $$ROOT对象并使用 $replaceRoot 替换为 root

  • $group重建 items再次数组,按 _id 分组并获得第一 username并构建 items阵列
  • db.players.aggregate([
      { $unwind: "$items" },
      {
        $lookup: {
          from: "items",
          let: {
            itemId: { $toObjectId: "$items.itemId" },
            items: "$items"
          },
          pipeline: [
            { $match: { $expr: { $eq: ["$_id", "$$itemId" ] } } },
            { $replaceRoot: { newRoot: { $mergeObjects: ["$$items", "$$ROOT"] } } }
          ],
          as: "items"
        }
      },
      {
        $group: {
          _id: "$_id",
          username: { $first: "$username" },
          items: { $push: { $first: "$items" } }
        }
      }
    ])
    
    Playground

    使用 $map 的第二个选项,并且没有 $unwind ,
  • $addFieldsitems转换 itemId使用 $toObjectId 将字符串转换为对象类型 ID和 $map
  • $lookup加入items收藏
  • $project显示必填字段,并合并 items数组和 itemsCollection使用 $map迭代项目数组的循环 $filter获得匹配 itemId$first从返回结果中获取第一个对象,$mergeObject合并当前对象和从 $first 返回的对象
  • db.players.aggregate([
      {
        $addFields: {
          items: {
            $map: {
              input: "$items",
              in: {
                $mergeObjects: ["$$this", { itemId: { $toObjectId: "$$this.itemId" } }]
              }
            }
          }
        }
      },
      {
        $lookup: {
          from: "items",
          localField: "items.itemId",
          foreignField: "_id",
          as: "itemsCollection"
        }
      },
      {
        $project: {
          username: 1,
          items: {
            $map: {
              input: "$items",
              as: "i",
              in: {
                $mergeObjects: [
                  "$$i",
                  {
                    $first: {
                      $filter: {
                        input: "$itemsCollection",
                        cond: { $eq: ["$$this._id", "$$i.itemId"] }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ])
    
    Playground

    关于MongoDB $lookup 和 $map 对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65047670/

    相关文章:

    node.js - 如何读取 Handlebars 中对象数组的属性?

    arrays - 在 MongoDB 中查找包含专门包含特定文档的数组的文档

    asp.net-mvc - ASP.NET MVC 3 - Web 应用程序 - 高效聚合数据

    JavaScript MongoDB 查询返回未定义

    node.js - mongodb在nodejs集合中找不到

    angularjs - 如何将json对象传递给node js服务器

    node.js - MongoDB 性能问题,可能是由于使用 native MongoDB 驱动程序在 NodeJS 项目中忽略了投影

    mongodb - 了解性能 : mongo aggregation vs count

    java - 有关系和正确的实践

    python - Pandas :计算两列的不同组合并添加到同一数据框