【问题标题】:MongoDB Aggregation for every element of array field of a document文档的数组字段的每个元素的 MongoDB 聚合
【发布时间】:2021-04-28 07:47:04
【问题描述】:

我有 2 个收藏 -

学生合集(学生文档样本)

{
'id': '123',
'name': 'john',
'age': 25,
'fav_colors': ['red', 'black'],
'marks_in_subjects': [
    {
     'marks': 90,
     'subject_id': 'abc'
    },
    {
     'marks': 92,
     'subject_id': 'def'
    }
 ]
}

主题集合(2 个示例文档)

{
'id': 'abc',
'name': 'math'
},
{
'id': 'def',
'name': 'physics'
}

当我查询 id: '123' 的学生文档时,我希望结果输出为:

{
'id': '123',
'name': 'john',
'age': 25,
'fav_colors': ['red', 'black'],
'marks_in_subjects': [
    {
     'marks': 90,
     'subject_id': 'abc',
     'subject_name': 'math'
    },
    {
     'marks': 92,
     'subject_id': 'def',
     'subject_name': 'physics'
    }
 ]
}

现在,我阅读了 MongoDB 聚合管道和操作符文档,但我仍然不知道如何实现这一点。疑问仍然存在,因为我什至不确定这是否可以在 mongo 聚合管道的帮助下实现,因为 JOIN 发生在学生文档中数组字段的每个元素的此处。

如果有人可以在这里提供帮助,那将非常有帮助。谢谢

【问题讨论】:

    标签: mongodb join aggregation-framework


    【解决方案1】:
    • $match你的条件
    • $unwind解构marks_in_subjects数组
    • $lookupsubjects 收藏
    • $addFields 从返回主题中获取第一个元素 name
    • $group by id 并重构 marks_in_subjects 数组,并使用 $first 运算符添加您所需的根文档字段
    db.students.aggregate([
      { $match: { id: "123" } },
      { $unwind: "$marks_in_subjects" },
      {
        $lookup: {
          from: "subjects",
          localField: "marks_in_subjects.subject_id",
          foreignField: "id",
          as: "marks_in_subjects.subject_name"
        }
      },
      {
        $addFields: {
          "marks_in_subjects.subject_name": {
            $arrayElemAt: ["$marks_in_subjects.subject_name.name", 0]
          }
        }
      },
      {
        $group: {
          _id: "$id",
          name: { $first: "$name" },
          age: { $first: "$age" },
          fav_colors: { $first: "$fav_colors" },
          marks_in_subjects: { $push: "$marks_in_subjects" }
        }
      }
    ])
    

    Playground


    没有$unwind阶段的第二个选项,

    • $match你的条件
    • $lookupsubjects 合集
    • $addFieldssubjects 获取主题名称
      • $map 迭代 marks_in_subjects 数组的循环
      • $reduce 迭代 subjects 数组的循环并检查条件如果 subject_id 匹配则返回主题 name
      • $mergeObjects 合并marks_in_subjects 的当前对象和新字段subject_name
    • $unset 删除 subjects 数组,因为它现在不需要
    db.students.aggregate([
      { $match: { id: "123" } },
      {
        $lookup: {
          from: "subjects",
          localField: "marks_in_subjects.subject_id",
          foreignField: "id",
          as: "subjects"
        }
      },
      {
        $addFields: {
          marks_in_subjects: {
            $map: {
              input: "$marks_in_subjects",
              as: "m",
              in: {
                $mergeObjects: [
                  "$$m",
                  {
                    subject_name: {
                      $reduce: {
                        input: "$subjects",
                        initialValue: "",
                        in: {
                          $cond: [{ $eq: ["$$this.id", "$$m.subject_id"]}, "$$this.name", "$$value"]
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      },
      { $unset: "subjects" }
    ])
    

    Playground

    【讨论】:

    • 嘿@turivishal-谢谢哥们。有效。非常感谢。然而,我还有一个疑问。假设学生集合中也有名称字段,我怎样才能在输出文档中获取名称字段?我知道有一种解决方案可以在管道的小组阶段推送名称字段。但是,将 name 字段设置为数组。如何在输出中添加名称字段作为键值字段?
    • 你只需要name字段还是其他必填字段?
    • 我的意思是我希望原始文档中的所有其他字段都保留在最终生成的文档中。因此,如果原始学生文档没有其他字段,我希望他们在学科字段的标记中添加学科名称后保留在最终生成的文档中。我希望我很清楚。再次感谢您抽出时间。
    • 你能不能只显示你的预期结果,只是从操场上改变结果并在这里分享。
    • @turivishal- 我已经更新了问题详细信息中的输入和输出 :)
    【解决方案2】:

    演示 - https://mongoplayground.net/p/H5fHpfWz5VH

    db.Students.aggregate([
      {
        $unwind: "$marks_in_subjects" //  break into individual documents
      },
      {
        "$lookup": { // get subject details
          "from": "Subjects",
          "localField": "marks_in_subjects.subject_id",
          "foreignField": "id",
          "as": "subjects"
        }
      },
      {
        $set: { // set name
          "marks_in_subjects.name": "subjects.0.name" // pick value from 0 index
        }
      },
      {
        $group: { // join document back by id
          _id: "$_id",
          marks_in_subjects: { $push: "$marks_in_subjects" }
        }
      }
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-14
      • 2015-04-01
      • 2021-01-04
      • 2019-02-02
      • 2019-10-27
      • 2021-10-24
      • 1970-01-01
      • 2016-07-20
      相关资源
      最近更新 更多