MongoDB 聚合文档的数组字段的每个元素

时间:2021-04-28 07:47:04

标签: mongodb join aggregation-framework

我有 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 在这里针对学生文档中数组字段的每个元素发生。

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

2 个答案:

答案 0 :(得分:3)

演示 - 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" }
    }
  }
])

答案 1 :(得分:2)

  • $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