简体   繁体   English

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

[英]MongoDB Aggregation for every element of array field of a document

I have 2 collections -我有 2 个 collections -

Student collection (sample student document)学生合集(学生文件样本)

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

Subjects collection (2 sample documents)主题集合(2 个样本文件)

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

When I query for student document for id: '123', I want the resulting output as:当我查询 id: '123' 的学生文档时,我希望得到的 output 为:

{
'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'
    }
 ]
}

Now, I read the MongoDB aggregation pipelines and operators document, still, I am clueless as to how to achieve this.现在,我阅读了 MongoDB 聚合管道和操作员文档,但我仍然对如何实现这一点一无所知。 The doubt persists because I am not even sure if this is possible with the help of mongo aggregation pipelines since JOIN happens here for every element of the array field in the student document.疑问仍然存在,因为我什至不确定这是否可以在 mongo 聚合管道的帮助下实现,因为 JOIN 发生在学生文档中数组字段的每个元素的此处。

It would be really helpful if anyone can help here.如果有人可以在这里提供帮助,那将非常有帮助。 Thanks谢谢

Demo - https://mongoplayground.net/p/H5fHpfWz5VH演示 - 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" }
    }
  }
])
  • $match you conditions $match你的条件
  • $unwind deconstruct marks_in_subjects array $unwind解构marks_in_subjects数组
  • $lookup with subjects collection $lookupsubjects集合
  • $addFields to get first element name from return subject $addFields从返回主题中获取第一个元素name
  • $group by id and reconstruct marks_in_subjects array and also add your required field of root document using $first operator $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操场


Second option without $unwind stage,没有$unwind阶段的第二个选项,

  • $match you conditions $match你的条件
  • $lookup with subjects collection $lookupsubjects集合
  • $addFields to get subject name from subjects $addFieldssubjects中获取主题名称
    • $map to iterate loop of marks_in_subjects array $map迭代marks_in_subjects数组的循环
    • $reduce to iterate loop of subjects array and check condition if subject_id match then return subject name $reduce迭代subjects数组的循环并检查条件是否subject_id匹配然后返回主题name
    • $mergeObjects to merge current object of marks_in_subjects and new field subject_name $mergeObjects合并当前 object 的marks_in_subjects和新字段subject_name
  • $unset to remove subjects array because its not needed now $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操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM