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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 22:23:11