【问题标题】:Mongoose join two collections and get only specific fields from the joined collectionMongoose 加入两个集合并从加入的集合中仅获取特定字段
【发布时间】:2020-10-10 19:37:43
【问题描述】:

我在 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'
        }
    }
 ]);

但这个结果并不是我所希望的那样。任何想法如何实现这一目标?我很乐意为您提供任何帮助。谢谢!

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    你可以试试,

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


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

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

    【讨论】:

    • 顺便说一句,如果我要在现有的聚合语句中添加另一个集合呢?
    • 你可以,使用查找加入。
    • 我不确定,但您的架构结构和 populate() 不可能。
    • 好的,谢谢!顺便说一句,我在这里有一个新问题:stackoverflow.com/questions/64339320/…希望你能帮助我。
    猜你喜欢
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 2020-05-12
    • 2018-06-03
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    相关资源
    最近更新 更多