Mongoose join two collections and get only specific fields from the joined collection

人盡茶涼 提交于 2021-02-11 06:55:00

问题


I have a problem joining two collections in mongoose. I have two collections namely: student and exams.

Student model:

{
  fullname: { type: String, required: true },
  email: { type: String, required: true },
}

Exams model:

{
  test: { type: String, required: false },
  top10: [
    type: {
      studentId: { type: String, required: true },
      score: { type: Number, required: false },
    }
  ]
}

Now, I want to join them two by studentId. The result should be:

{
 "test": "Sample Test #1",
 "students": [
            {
                "studentId": "5f22ef443f17d8235332bbbe",
                "fullname": "John Smith",
                "score": 11
            },
            {
                "studentId": "5f281ad0838c6885856b6c01",
                "fullname": "Erlanie Jones",
                "score": 9
            },
            {
                "studentId": "5f64add93dc79c0d534a51d0",
                "fullname": "Krishna Kumar",
                "score": 5
            }
        ]
 }

What I did was to use aggregate:

 return await Exams.aggregate([
    {$lookup:
        {
            from: 'students',
            localField: 'top10.studentId',
            foreignField: '_id',
            as: 'students'
        }
    }
 ]);

But this result is not what I had hoped it should be. Any ideas how to achieve this? I would gladly appreciate any help. Thanks!


回答1:


You can try,

  • $lookup with students collection
  • $project to show required fields, $map to iterate loop of top10 array and inside use $reduce to get fullname from students and merge with top10 object using $mergeObjects
db.exams.aggregate([
  {
    $lookup: {
      from: "students",
      localField: "top10.studentId",
      foreignField: "_id",
      as: "students"
    }
  },
  {
    $project: {
      test: 1,
      students: {
        $map: {
          input: "$top10",
          as: "top10",
          in: {
            $mergeObjects: [
              "$$top10",
              {
                fullname: {
                  $reduce: {
                    input: "$students",
                    initialValue: 0,
                    in: {
                      $cond: [
                        { $eq: ["$$this._id", "$$top10.studentId"] },
                        "$$this.fullname",
                        "$$value"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

Playground


Second option you can use $unwind before $lookup,

  • $unwind deconstruct top10 array
  • $lookup with students collection
  • $addFields to convert students array to object using $arrayElemtAt
  • $group by _id and construct students array and push required fields
db.exams.aggregate([
  { $unwind: "$top10" },
  {
    $lookup: {
      from: "students",
      localField: "top10.studentId",
      foreignField: "_id",
      as: "students"
    }
  },
  { $addFields: { students: { $arrayElemAt: ["$students", 0] } } },
  {
    $group: {
      _id: "$_id",
      test: { $first: "$test" },
      students: {
        $push: {
          studentId: "$top10.studentId",
          score: "$top10.score",
          fullname: "$students.fullname"
        }
      }
    }
  }
])

Playground



来源:https://stackoverflow.com/questions/64278693/mongoose-join-two-collections-and-get-only-specific-fields-from-the-joined-colle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!