如何在Node.js Sequelize中获取TeacherId、SubjectId和CurriculumId均相同的记录并合并关联文档
嘿,这问题我熟!刚好之前做过类似的需求,用Node.js + Sequelize处理这种按TeacherId、SubjectId、CurriculumId分组,合并文档为数组的场景,有两种比较常用的方案,我给你详细说说~
方案一:查询所有数据后用JavaScript分组处理(灵活易调试)
这种方式先把符合条件的所有记录查出来,再用JS逻辑做分组合并,好处是逻辑直观,关联复杂表时更容易调整。
第一步:查询目标数据
假设你的模型是TeacherDocument,关联了Curriculum和Subject表,先查询包含所有需要字段的记录:
const { sequelize } = require('./models'); // 导入你的Sequelize实例 const TeacherDocument = require('./models/TeacherDocument'); const Curriculum = require('./models/Curriculum'); const Subject = require('./models/Subject'); async function getMergedDocuments(teacherId) { // 查询所有关联的记录 const rawDocuments = await TeacherDocument.findAll({ attributes: [ 'TeacherId', 'CurriculumId', 'SubjectId', 'id', 'name', 'path', 'size', 'createdAt' ], include: [ { model: Curriculum, attributes: ['curriculum_name'] // 只取需要的课程名称字段 }, { model: Subject, attributes: ['subject_name'] // 只取需要的科目名称字段 } ], where: { TeacherId: teacherId } // 指定要查询的教师ID }); // 第二步:分组合并文档数组 const mergedMap = new Map(); rawDocuments.forEach(doc => { // 用 CurriculumId + SubjectId 作为分组的唯一标识(TeacherId已固定) const groupKey = `${doc.CurriculumId}-${doc.SubjectId}`; if (!mergedMap.has(groupKey)) { // 初始化分组对象 mergedMap.set(groupKey, { CurriculumId: doc.CurriculumId, curriculum_name: doc.Curriculum.curriculum_name, SubjectId: doc.SubjectId, subject_name: doc.Subject.subject_name, doc: [] }); } // 将当前文档信息加入分组的doc数组 mergedMap.get(groupKey).doc.push({ id: doc.id, name: doc.name, path: doc.path, size: doc.size, createdAt: doc.createdAt }); }); // 将Map转为数组,就是你要的最终格式 return { data: Array.from(mergedMap.values()) }; }
方案二:用MySQL JSON函数直接分组查询(性能更优)
如果你的数据量比较大,直接用MySQL的JSON_ARRAYAGG和JSON_OBJECT函数在数据库层面完成分组合并,能减少传输到Node.js的数据量,效率更高(需要MySQL 5.7及以上版本支持JSON函数)。
执行原生SQL查询
async function getMergedDocuments(teacherId) { const [results] = await sequelize.query( `SELECT td.CurriculumId, c.curriculum_name, td.SubjectId, s.subject_name, JSON_ARRAYAGG( JSON_OBJECT( 'id', td.id, 'name', td.name, 'path', td.path, 'size', td.size, 'createdAt', td.createdAt ) ) AS doc FROM TeacherDocument td LEFT JOIN Curriculum c ON td.CurriculumId = c.id LEFT JOIN Subject s ON td.SubjectId = s.id WHERE td.TeacherId = :teacherId GROUP BY td.CurriculumId, td.SubjectId;`, { replacements: { teacherId: teacherId }, // 传入参数避免SQL注入 type: sequelize.QueryTypes.SELECT } ); return { data: results }; }
两种方案对比
- 方案一:逻辑简单直观,容易调试和修改,适合关联表结构复杂、数据量不大的场景。
- 方案二:数据库层面完成聚合,减少数据传输,性能更好,适合数据量大的场景,但需要熟悉MySQL JSON函数的用法。
你可以根据自己的实际场景选择合适的方案,测试后就能得到你想要的输出格式啦~
内容的提问来源于stack exchange,提问作者Dawood Shahzad
相关产品推荐
相关产品推荐

