mongodb - 在 $lookup 之后将原始对象数组合并到 "as"字段中

标签 mongodb mongodb-query aggregation-framework

我有一个 hero 集合,其中每个 hero 文档如下所示:

{
    _id:'the-name-of-the-hero',
    name: 'Name of Hero',
    (...), //other properties to this hero

    relations: [
        {
            hero: 'the-id-of-another-hero',
            relationType: 'trust'
        },
        {
            hero: 'yet-another-id-of-another-hero',
            relationType: 'hate'
        }
    ]
}

relations.hero 指向另一个英雄的 _id。我需要获取更多相关英雄的信息,因此我使用聚合 $lookup 将每个英雄与“英雄”集合进行匹配,以获取它的 name(和其他数据,但针对问题简化了项目)。这里是当前工作的查询,记录在案:

let aggregate = db.collection('hero').aggregate([
    // grabbing an specific hero
    { $match: { _id } },
    //populate relations
    {
        $lookup: {
            from: 'hero',
            let: { letId: '$relations.hero' }, //create a local variable for the pipeline to use
            // localField: "relations.hero", //this would bring entire hero data, which is unnecessary
            // foreignField: "_id",  //this would bring entire hero data, which is unnecessary
            pipeline: [
                //match each $relations.hero (as "$$letId") in collection hero's (as "from") $_id
                { $match: { $expr: { $in: ['$_id', '$$letId'] } } },
                //grab only the _id and name of the matched heroes
                { $project: { name: 1, _id: 1 } },
                //sort by name
                { $sort:{ name: 1 } }
            ],
            //replace the current relations with the new relations
            as: 'relations',
        },
    }
]).toArray(someCallbackHere);

简而言之,$lookuphero 集合上使用 pipeline 匹配每个 relations.hero 和只带回 _idname(在 UI 上打印真实姓名)并用这个新的 替换当前的 relations关系,生成文档为:

{
    _id:'the-name-of-the-hero',
    name: 'Name of Hero',
    (...), //other properties to this hero
    relations: [
        {
            _id: 'the-id-of-another-hero',
            name: 'The Real Name of Another Hero',
        },
        {
            _id: 'yet-another-id-of-another-hero',
            name: 'Yet Another Real Name of Another Hero',
        }
    ]
}

问题:

我可以在管道上添加什么以使其将匹配的英雄与原始 relations 合并,以便不仅具有投影的 _idname ,还有原来的relationType?即有如下结果:

{
    _id:'the-name-of-the-hero',
    name: 'Name of Hero',
    (...), //other properties to this hero
    relations: [
        {
            _id: 'the-id-of-another-hero',
            name: 'The Real Name of Another Hero',
            relationType: 'trust' //<= kept from the original relations
        },
        {
            _id: 'yet-another-id-of-another-hero',
            name: 'Yet Another Real Name of Another Hero',
            relationType: 'hate' //<= kept from the original relations
        }
    ]
}

我尝试将 导出为:'relationsFull',然后尝试将 $push$mergeObjects 作为聚合下一步的一部分但没有运气。我尝试做与管道步骤相同的操作(而不是新的聚合步骤),但总是以 relations 为空数组结束..

我将如何编写一个新的聚合步骤来将旧的 relations 对象与新查找的 relations 对象合并?

注意:考虑 MongoDB 3.6 或更高版本(即,不需要 $unwind 数组,至少对于 $lookup).如果该信息很重要,我正在使用 Node.js 驱动程序进行查询。

最佳答案

您可以使用以下聚合

db.collection("hero").aggregate([
  { "$match": { _id } },
  { "$unwind": "$relations" },
  { "$lookup": {
    "from": "hero",
    "let": { "letId": "$relations.hero" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": ["$_id", "$$letId"] } } },
      { "$project": { "name": 1 } }
    ],
    "as": "relation"
  }},
  { "$unwind": "$relation" },
  { "$addFields": { "relations.name": "$relation.name" }},
  { "$group": {
    "_id": "$_id",
    "relations": { "$push": "$relations" },
    "name": { "$first": "$name" },
    "rarity": { "$first": "$rarity" },
    "classType": { "$first": "$classType" }
  }}
])

或者你也可以使用它

db.collection("hero").aggregate([
  { "$match": { _id } },
  { "$lookup": {
    "from": "hero",
    "let": { "letId": "$relations.hero" },
    "pipeline": [
      { "$match": { "$expr": { "$in": ["$_id", "$$letId"] } } },
      { "$project": { "name": 1 } }
    ],
    "as": "lookupRelations"
  }},
  { "$addFields": {
    "relations": {
      "$map": { 
        "input": "$relations",
        "as": "rel",
        "in": {
          "$mergeObjects": [
            "$$rel",
            { "name": { "$arrayElemAt": ["$lookupRelations.name", { "$indexOfArray": ["$lookupRelations._id", "$$rel._id"] }] }}
          ]
        }
      }
    }
  }}
])

关于mongodb - 在 $lookup 之后将原始对象数组合并到 "as"字段中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54832677/

相关文章:

node.js - 使用索引时MongoDB查询排序超出内存限制

c# - 如何在 C# Mongodb 强类型驱动程序中基于嵌套数组元素进行过滤

javascript - 如何使用 mongo 聚合循环遍历数组并返回所需的文档?

MongoDB WinningPlan IDHACK

mongodb - Mongo shell聚合查询问题

node.js - 通过值或变量设置项目阶段键

regex - 整数值的 MongoDB 正则表达式搜索

mongodb - 如何加快聚合中的 $group 阶段

python - 迭代 pyspark Dataframe,然后为每一行与 mongoDB 交互

javascript - 无法读取未定义的属性映射