You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB多$group聚合查询:按学生、模块、考试整理成绩

MongoDB聚合管道优化:按学生维度整理成绩

数据库Schema

Module: {
    code_module: String,
    designation_module: String,
    année: Number,
    coéfficient: Number,
    listEpreuves: [{
        code_epreuve: String,
        nature_epreuve: String,
        Resultat: [{
            student_lastname: String,
            student_firstname: String,
            note: Number
        }]
    }]
}

需求目标

按学生维度整理各模块下的考试成绩,输出示例如下:

"john smith": {
    "biologie": {
        "epreuve1": 12,
        "epreuve2": 13,
        "epreuve3": 7
    },
    "physique": {
        "epreuve1": 13, 
        "epreuve2": 18
    },
    "Maths": {
        "epreuve1": 17,
        "epreuve2": 10,
        "epreuve3": 7.5
    }
}

现有问题聚合管道

你当前的聚合管道存在字段不匹配、嵌套数组处理不当等问题,原代码如下:

Moddulle.aggregate([
  {
    $sort: {
      "listEpreuves.resultat.nom_etudiant": 1,
      "listEpreuves.resultat.prenom_etudiant": 1
    }
  },
  {
    $group: {
      _id: {
        nom: "$listEpreuves.resultat.nom_etudiant",
        prenom: "$listEpreuves.resultat.prenom_etudiant"
      },
      modules: {
        $push: {
          code_moddulle: "$code_moddulle",
          designation_moddulle: "$designation_moddulle",
          epreuves: "$listEpreuves"
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      nom: "$_id.nom",
      prenom: "$_id.prenom",
      modules: 1
    }
  }
])

问题分析

  1. 字段名称不匹配:Schema中字段为student_lastname/student_firstname,但代码中误用nom_etudiant/prenom_etudiant;集合名Module被错写为Moddulle,code_module错写为code_moddulle,导致数据无法正确关联。
  2. 嵌套数组未展开:listEpreuves和Resultat都是嵌套数组,直接分组会将整个数组作为整体处理,无法拆分到单个学生、单个考试的维度。
  3. 分组逻辑错误:用数组字段作为分组_id,无法生成唯一有效的分组键,导致结果不符合预期。

正确的聚合管道

Module.aggregate([
  // 展开listEpreuves数组,将每个考试拆分为单独文档
  { $unwind: "$listEpreuves" },
  // 展开Resultat数组,将每个学生的成绩拆分为单独文档
  { $unwind: "$listEpreuves.Resultat" },
  // 按学生姓名分组,收集该学生所有成绩记录
  {
    $group: {
      _id: {
        lastname: "$listEpreuves.Resultat.student_lastname",
        firstname: "$listEpreuves.Resultat.student_firstname"
      },
      studentGrades: {
        $push: {
          module: "$designation_module",
          epreuve: "$listEpreuves.code_epreuve",
          note: "$listEpreuves.Resultat.note"
        }
      }
    }
  },
  // 整理成绩结构,按模块分类
  {
    $project: {
      _id: 0,
      studentName: { $concat: ["$_id.firstname", " ", "$_id.lastname"] },
      grades: {
        $arrayToObject: {
          $map: {
            input: { $setUnion: ["$studentGrades.module"] },
            as: "module",
            in: {
              k: "$$module",
              v: {
                $arrayToObject: {
                  $map: {
                    input: { $filter: { input: "$studentGrades", cond: { $eq: ["$$this.module", "$$module"] } } },
                    as: "grade",
                    in: { k: "$$grade.epreuve", v: "$$grade.note" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  // 将学生姓名设为顶级键,匹配目标输出格式
  {
    $replaceRoot: {
      newRoot: {
        $arrayToObject: [[{ k: "$studentName", v: "$grades" }]]
      }
    }
  }
])

管道步骤说明

  1. $unwind:两次展开嵌套数组,确保每条文档对应单个学生的单个考试成绩,为后续分组提供基础。
  2. $group:按学生姓名分组,统一收集该学生的所有成绩记录,包含模块、考试编号和分数信息。
  3. $project:
    • 拼接学生姓与名为完整姓名;
    • 通过$setUnion提取唯一模块列表,再用$map和$arrayToObject将每个模块下的考试成绩转换为键值对结构。
  4. $replaceRoot:将学生姓名作为顶级键,输出完全符合需求的格式。

内容的提问来源于stack exchange,提问作者Mouni19

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:17:03