【问题标题】:mongoose aggregate how to map multiple collections into one Array猫鼬聚合如何将多个集合映射到一个数组中
【发布时间】:2021-08-05 07:59:45
【问题描述】:

我有四个不同的系列。从中三连一:

Collection_A = {
    _id: 1
    name: A
    includes: [
        {
            _id: 1,
            includes_id: 222,
        },
        {
            _id: 2,
            includes_id: 333
        }
    ] 
}

Collection_B = {
    _id: 222,
    type: Computer,
    name: Computer,
    ref_id: 1
}

Collection_C = {
    _id: 333,
    type: Human,
    name: Human,
    ref_id: 1
}

Collection_D = {
    _id: 444,
    type: Animal,
    name: Animal,
    ref_id: 1
}

所以集合 A 可以在包含对象中包含集合 B、C 和 D。它至少包含一个集合。

所以Collection A中的includes对象中有includes_id,即Collection B、C和D中的_id。 Collection A 中的 _id 是 Collection B、C 和 D 中的 ref_id。

我现在的问题是,聚合只需要最后一个映射的集合。

我现在的代码如下:

     Collection_A.aggregate([
        {
          $lookup: {
            from: "collectionb",
            localField: "includes.includes_id",
            foreignField: "_id",
            as: "colb",
          },
        },
        {
          $lookup: {
            from: "collectionc",
            localField: "includes.includes_id",
            foreignField: "_id",
            as: "colc",
          },
        },
        {
          $project: {
            _id: 1,
            status: 1,
            type: 1,
            includes_list: {
              $map: {
                input: "$includes",
                as: "i",
                in: {
                  $arrayElemAt: [
                        {
                        $filter: {
                            input: "$colb",
                            cond: {
                            $eq: ["$$this._id", "$$i.includes_id"],
                            },
                        },
                        },
                        0,
                    ],
                    $arrayElemAt: [
                        {
                        $filter: {
                            input: "$colc",
                            cond: {
                            $eq: ["$$this._id", "$$i.includes_id"],
                            },
                        },
                        },
                        0,
                    ],
                },
              },
            },
          },
        },
      ]);

我尝试在每次查找时使 $lookup 相同,但它只取最后一次查找的数据,而其他数据显示为空。 所以我将 $lookup 设为唯一,并将两个 ins 放入 map 中,但最后一次查找的数据也显示出来了,其他的则为 null。

当我做这样的映射时:

includes_list: {
    $map: {
    input: "$icludes",
    as: "i",
    in: {
        {
            Col_A : {
            $arrayElemAt: [
                {
                    $filter: {
                        input: "$A",
                        cond: {
                        $eq: ["$$this._id", "$$i.includes"],
                        },
                    },
                },
                0,
            ],
            },
            Col_B : {
            $arrayElemAt: [
                {
                    $filter: {
                        input: "$B",
                        cond: {
                        $eq: ["$$this._id", "$$i.includes"],
                        },
                    },
                },
                0,
            ],
            }
        }
    },
    },
}

它有效。但没有正确的输出,因为我需要在一个数组中包含 includes_list。

我想要的输出如下:

{
    includes: [
        {
            _id: 1,
            name: Computer,
            includes_list: [
                {
                    _id: 222,
                    type: Computer,
                    name: Computer,
                    ref_id: 1
                },
                {
                    _id: 333,
                    type: Human,
                    name: Human,
                    ref_id: 1
                },
            ]
        },
        {
            _id: 2,
            name: Animal,
            includes_list: [
                {
                    _id: 333,
                    type: Human,
                    name: Human,
                    ref_id: 2
                },
            ]
        }
    ]
}

不胜感激!

【问题讨论】:

    标签: arrays mongodb dictionary mongoose aggregate


    【解决方案1】:

    对于这种情况, $facet 帮助对传入数据进行分类

    db.Collection_A.aggregate([
      { $unwind: "$includes },
      {
        "$facet": {
          "joinB": [            
            {
              "$lookup": {
                "from": "Collection_B", "localField": "includes.includes_id",
                "foreignField": "_id", "as": "includes.includes_list"
              }
            },
            {
              "$group": {
                "_id": "$_id",
                "name": { "$first": "$name" },
                includes: { $push: "$includes" }
              }
            }
          ],
          "joinC": [            
            {
              "$lookup": {
                "from": "Collection_C", "localField": "includes.includes_id",
                "foreignField": "_id", "as": "includes.includes_list"
              }
            },
            {
              "$group": {
                "_id": "$_id",
                "name": { "$first": "$name" },
                includes: { $push: "$includes" }
              }
            }
          ],
          "joinD": [
            {
              "$lookup": {
                "from": "Collection_D", "localField": "includes.includes_id",
                "foreignField": "_id", "as": "includes.includes_list"
              }
            },
            {
              "$group": {
                "_id": "$_id",
                "name": { "$first": "$name" },
                includes: { $push: "$includes" }
              }
            }
          ],
          
        }
      },
      {
        $project: {
          combined: {
            "$concatArrays": [ "$joinB", "$joinC", "$joinD" ]
          }
        }
      },
      { "$unwind": "$combined" },
      {
        "$replaceRoot": { "newRoot": "$combined" }
      },
      {
        "$project": {
          _id: 1,
          name: 1,
          includes: {
            $filter: {
              input: "$includes",
              cond: {
                $ne: [ "$$this.includes_list",[] ]
              }
            }
          }
        }
      }
    ])
    

    工作Mongo playground

    注意:我觉得这是你遵循的一种反模式。如果您处于项目的早期阶段,如果我没记错的话,最好改变结构。

    【讨论】:

    • 您对如何以更好的方式进行操作有什么建议吗?
    • @soptro 我不知道您正在使用的域模型。但是您可以使用 OOP 概念,例如继承。例如:Human extends AnimalPets extends Animal。所以Animalname, age,type //HUMAN or PETHumanlanguagePetssome other fields。由于两者都是 Animal 的扩展形式,因此您可以将两者放在一个集合中。当您在后端检索时,您可以使用instanceOf 来划分使用type 的对象。这只是一个例子
    • 不,它没有。我完全改变了我的系统。
    猜你喜欢
    • 2023-03-31
    • 1970-01-01
    • 2020-03-13
    • 2023-04-04
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    相关资源
    最近更新 更多