Warm tip: This article is reproduced from serverfault.com, please click

其他-MongoDB $ lookup和$ map对象数组

(其他 - MongoDB $lookup and $map array of objects)

发布于 2020-11-28 08:12:14

我想做几天,但找不到任何成功

我使用的是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
        }
    ]
}
Questioner
Asaf
Viewed
22
turivishal 2020-11-28 16:34:51
  • $unwind解构items数组
  • $lookup要加入items收藏集,请itemsId使用将其转换为对象ID后传递给let,$toObjectId然后传递items对象,
    • $match itemId 状况
    • $mergeObject合并items对象和$$ROOT对象并替换为root$replaceRoot
  • $groupitems再次重建数组,分组_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" } }
    }
  }
])

操场


使用第二个选项$map,如果没有$unwind

  • $addFields对于items转换itemId使用字符串对象类型ID$toObjectId$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"] }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

操场