猫鼬加入两个集合,并且仅从加入的集合中获取特定字段

时间:2020-10-09 10:59:02

标签: node.js mongodb mongoose

在猫鼬中加入两个收藏集时遇到问题。我有两个收藏集:学生和考试。

学生模型:

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

考试模式:

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

现在,我想通过 studentId 将他们两个同时加入。结果应该是:

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

我所做的是使用聚合:

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

但是这个结果不是我希望的那样。任何想法如何实现这一目标?我将很高兴提供任何帮助。谢谢!

1 个答案:

答案 0 :(得分:0)

您可以尝试

  • $lookupstudents集合
  • $project显示必填字段,$map迭代top10数组循环,并在内部使用$reduce从学生那里获取全名,并使用$mergeObjects与top10对象合并
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


第二个选项,您可以在$unwind之前使用$lookup

  • $unwind解构top10数组
  • $lookupstudents集合
  • $addFields使用$arrayElemtAt
  • 将学生数组转换为对象 _id的
  • $group并构造学生数组并推送必填字段
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