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

文档数组字段每个元素的MongoDB聚合,mongodb,join,aggregation-framework,Mongodb,Join,Aggregation Framework,我有两个系列- 学生资料集(学生资料样本) 主题收集(2份样本文档) 当我查询id为“123”的学生文档时,我希望结果输出为: { 'id': '123', 'name': 'john', 'age': 25, 'fav_colors': ['red', 'black'], 'marks_in_subjects': [ { 'marks': 90, 'subject_id': 'abc', 'subject_name': 'math' },

我有两个系列-

学生资料集(学生资料样本)

主题收集(2份样本文档)

当我查询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聚合管道的帮助下是否可以实现,因为在这里,学生文档中数组字段的每个元素都会发生连接

如果有人能帮上忙,那就太好了。谢谢

  • $match
  • $unwind
    解构
    主题中的标记
    数组
  • $lookup
    主题
    集合
  • $addFields
    从返回主题获取第一个元素
    name
  • $group
    by
    id
    并重建
    标记\u主题中的\u
    数组,还可以使用
    $first
    操作符添加根文档的必填字段


第二个选项,不带
$unwind
阶段

  • $match
  • $lookup
    主题
    集合
  • $addFields
    主题
    • $map
      迭代
      主题中标记的循环
    • $reduce
      迭代
      主题的循环
      数组,检查条件是否
      主题id
      匹配,然后返回主题
      名称
    • $mergeObjects
      标记的当前对象合并到\u subject
      和新字段
      subject\u name
  • $unset
    删除
    主题
    数组,因为现在不需要它

  • $match
  • $unwind
    解构
    主题中的标记
    数组
  • $lookup
    主题
    集合
  • $addFields
    从返回主题获取第一个元素
    name
  • $group
    by
    id
    并重建
    标记\u主题中的\u
    数组,还可以使用
    $first
    操作符添加根文档的必填字段


第二个选项,不带
$unwind
阶段

  • $match
  • $lookup
    主题
    集合
  • $addFields
    主题
    • $map
      迭代
      主题中标记的循环
    • $reduce
      迭代
      主题的循环
      数组,检查条件是否
      主题id
      匹配,然后返回主题
      名称
    • $mergeObjects
      标记的当前对象合并到\u subject
      和新字段
      subject\u name
  • $unset
    删除
    主题
    数组,因为现在不需要它
演示-

演示-


嘿@turivishal-谢谢你,伙计。成功了。谢谢。然而,我还有一个疑问。假设students集合中也有name字段,那么如何在输出文档中也获得name字段?我知道有一种解决方案可以在管道的分组阶段推送名称字段。但是,它将名称字段设置为数组。如何在输出中添加名称字段作为键值字段?您只需要名称字段或其他必需字段?我的意思是,我希望原始文档中的所有其他字段都保留在最终生成的文档中。因此,如果原始的students文档有n个其他字段,我希望在将主题名称添加到marks in subject字段中后,它们将保留在最终生成的文档中。我希望我是清楚的。再次感谢您抽出时间来讨论这个问题。您可以展示您的预期结果吗?只需更改游乐场的结果并在此处共享。@Turivshal-我已更新了问题详细信息中的输入和输出:)嘿@Turivshal-谢谢老兄。成功了。谢谢。然而,我还有一个疑问。假设students集合中也有name字段,那么如何在输出文档中也获得name字段?我知道有一种解决方案可以在管道的分组阶段推送名称字段。但是,它将名称字段设置为数组。如何在输出中添加名称字段作为键值字段?您只需要名称字段或其他必需字段?我的意思是,我希望原始文档中的所有其他字段都保留在最终生成的文档中。因此,如果原始的students文档有n个其他字段,我希望在将主题名称添加到marks in subject字段中后,它们将保留在最终生成的文档中。我希望我是清楚的。再次感谢您给我时间。您能不能只显示您的预期结果,只需更改游乐场的结果并在此处共享。@turivishal-我已更新了问题详细信息中的输入和输出:)
{
'id': 'abc',
'name': 'math'
},
{
'id': 'def',
'name': 'physics'
}
{
'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'
    }
 ]
}
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" }
    }
  }
])
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" }
])
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" }
    }
  }
])