【问题标题】:How to use aggregate to group mongodb如何使用聚合对 mongodb 进行分组
【发布时间】:2020-11-16 20:59:44
【问题描述】:

我正在尝试用他的才华和才华媒体填充我的用户文档。但我得到了重复的对象。我想将人才作为一个对象,并将媒体与该人才放在一个数组中。

我的用户模型:

{
    _id: '5f1acd6e6985114f2c1567ea',
    name: 'test user',
    email: 'test@email.com'
}
    

人才模型

{
    _id: '5f1acd6e6985114f2c1567fa',
    categoryId: '5f1acd6e6985114f2c1567ga',
    userId: '5f1acd6e6985114f2c1567ea'
    level: '5',
}

人才媒体模式

{
    _id: 5f1acd6e6985114f2c156710',
    talentId: '5f1acd6e6985114f2c1567fa',
    media: 'file.jpg',
    fileType: 'image'
}

我有另一个存储类别的模型

{
    _id: '5f1acd6e6985114f2c1567ga',
    title: 'java'
}

我想要的结果如下

user: {
  _id: '',
  name: 'test user',
  email: 'test@email.com',
  talents: [
    {
      _id: '',
      level: '5',
      categoryId: {
        _id: '',
        title: 'java'
      },
      medias: [
        {
           _id: '',
           file: 'file1.jpg',
           fileType: 'image'
        },
        {
           _id: '',
           file: 'file2.jpg',
           fileType: 'image'
        },
      ]
    }
  ]
}

我还尝试在人才文件中添加人才媒体。但在 MongoDB 文档中找到的大部分不推荐使用。 有这样的人才模型是不是更好,

{
    _id: '5f1acd6e6985114f2c1567fa',
    categoryId: '5f1acd6e6985114f2c1567ga',
    userId: '5f1acd6e6985114f2c1567ea'
    level: '5',
    medias: [
        {
           _id: '',
           file: 'file1.jpg',
           fileType: 'image'
        },
        {
           _id: '',
           file: 'file2.jpg',
           fileType: 'image'
        },
    ]
}

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    你必须使用嵌套的$lookup

    • 使用 Talent Collection 查找并匹配 userId
    • $match 用于特定用户 _id 文档,在此处注释
    db.User.aggregate([
      /** add here
      Optional for single user
      {
        $match: {
          _id: "XXXXXXXXXXXX"
        }
      },
      */
      {
        $lookup: {
          from: "Talent",
          as: "talents",
          let: {
            userId: "$_id"
          },
          pipeline: [
            {
              $match: {
                $expr: {
                  $eq: [
                    "$$userId",
                    "$userId"
                  ]
                }
              }
            },
    
    • 我们现在在人才文档中,使用 Category Collection 查找并匹配 categoryId
    • $unwind category 因为它会返回数组,我们需要对象
            {
              $lookup: {
                from: "Category",
                as: "categoryId",
                localField: "categoryId",
                foreignField: "_id"
              }
            },
            {
              $unwind: {
                path: "$categoryId",
                preserveNullAndEmptyArrays: true
              }
            },
    
    • 我们再次进入人才文档并使用 人才媒体收藏 查找并匹配 talentId
    • $project 用于添加/删除不需要的字段,这里从 TalentMedia 中删除了 talentID 并从 Talent 中删除了 userId
            {
              $lookup: {
                from: "TalentMedia",
                as: "medias",
                let: {
                  talentId: "$_id"
                },
                pipeline: [
                  {
                    $match: {
                      $expr: {
                        $eq: [
                          "$$talentId",
                          "$talentId"
                        ]
                      }
                    }
                  },
                  {
                    $project: {
                      talentId: 0
                    }
                  }
                ]
              }
            },
            {
              $project: {
                userId: 0
              }
            }
          ]
        }
      }
    ])
    

    分段查询说明,可以按顺序组合。

    工作场所:https://mongoplayground.net/p/poIbvFUMvT4

    【讨论】:

    • 是的!你拯救了我的一天。这如何通过传递用户 _id 对单个用户起作用?
    • 但我得到的结果是一个数组。不作为用户对象。
    • 好的...你能不能给我一个演示,让只有媒体填充的人才阵列作为人才内部的阵列?没有用户详细信息。喜欢:talents:[{ _id, level, category: {_id, title }, medias: [{ _id, file, fileType }, {_id, file, fileType} ] }]这个
    【解决方案2】:

    您可以通过多次使用$lookup 来实现:

    db.users.aggregate([
      {
        $lookup: {
          from: "talents",
          let: {
            userId: "$_id"
          },
          pipeline: [
            {
              $match: {
                $expr: {
                  $eq: [
                    "$$userId",
                    "$userId"
                  ]
                }
              }
            },
            {
              $lookup: {
                from: "categories",
                let: {
                  categoryId: "$categoryId"
                },
                pipeline: [
                  {
                    $match: {
                      $expr: {
                        $eq: [
                          "$$categoryId",
                          "$_id"
                        ]
                      }
                    }
                  },
                  {
                    $project: {
                      _id: "",
                      title: 1
                    }
                  }
                ],
                as: "categoryId"
              }
            },
            {
              $lookup: {
                from: "talent_media",
                let: {
                  talentId: "$_id"
                },
                pipeline: [
                  {
                    $match: {
                      $expr: {
                        $eq: [
                          "$$talentId",
                          "$talentId"
                        ]
                      }
                    }
                  },
                  {
                    $project: {
                      _id: "",
                      file: "$media",
                      fileType: "$fileType"
                    }
                  }
                ],
                as: "medias"
              }
            },
            {
              $unwind: {
                path: "$categoryId",
                preserveNullAndEmptyArrays: true
              }
            },
            {
              $project: {
                _id: "",
                categoryId: 1,
                level: 1,
                medias: 1
              }
            }
          ],
          as: "talents"
        }
      },
      {
        $project: {
          _id: "",
          email: 1,
          name: 1,
          talents: 1
        }
      }
    ])
    

    *您可能需要调整集合名称。

    MongoPlayground

    【讨论】:

    猜你喜欢
    • 2023-01-20
    • 2019-05-19
    • 2019-01-31
    • 2020-12-29
    • 2018-06-26
    • 1970-01-01
    • 2016-04-18
    • 2019-06-29
    • 2020-09-15
    相关资源
    最近更新 更多