Node.js处理MySQL关联查询结果,构建嵌套JSON结构问题
问题分析与解决方案
核心原因排查
- 字段名冲突:LEFT JOIN时多表存在同名字段(如
Id),MySQL会自动覆盖后续字段值,导致你获取的Category.Id被覆盖为其他表的Id或直接返回undefined。 - 大小写/字段映射不匹配:数据库字段是下划线命名(如
category_id)或大小写格式(如CategoryID),但代码里用了错误的属性名(如Category.Id)访问。 - 遍历逻辑漏洞:构建嵌套结构时,未正确判断数组中已存在的分类,导致每次循环都新建分类对象,造成重复。
具体解决步骤
1. 修正SQL查询的字段别名
给查询结果的分类字段添加唯一别名,彻底避免字段冲突:
SELECT pc.Id AS category_id, pc.Name AS category_name, ps.Id AS skill_id, ps.Name AS skill_name, pm.Content AS message_content FROM Progress_Category pc LEFT JOIN Progress_Skill ps ON pc.Id = ps.CategoryId LEFT JOIN Progress_Message pm ON ps.Id = pm.SkillId
2. 调整Node.js代码的属性访问逻辑
根据查询结果的实际字段名,正确访问属性并构建嵌套结构:
// 假设flatResults是你的查询返回结果 const nestedCategories = []; flatResults.forEach(row => { // 查找当前分类是否已存在于数组中 let targetCategory = nestedCategories.find(cat => cat.id === row.category_id); if (!targetCategory) { // 不存在则创建新分类对象并推入数组 targetCategory = { id: row.category_id, name: row.category_name, skills: [] }; nestedCategories.push(targetCategory); } // 处理技能数据(避免空技能重复添加) if (row.skill_id) { let targetSkill = targetCategory.skills.find(skill => skill.id === row.skill_id); if (!targetSkill) { targetSkill = { id: row.skill_id, name: row.skill_name, messages: row.message_content ? [row.message_content] : [] }; targetCategory.skills.push(targetSkill); } else { // 追加消息(避免重复消息) if (row.message_content && !targetSkill.messages.includes(row.message_content)) { targetSkill.messages.push(row.message_content); } } } });
3. 验证字段映射一致性
如果使用ORM(如Sequelize),需确保模型字段与数据库字段映射正确:
// Sequelize模型示例:匹配数据库的大小写/下划线字段 const ProgressCategory = sequelize.define('Progress_Category', { id: { type: DataTypes.INTEGER, primaryKey: true, field: 'Id' // 对应数据库的大写Id字段 }, name: { type: DataTypes.STRING, field: 'Name' } });
4. 快速调试方法
遍历前打印第一条结果,确认返回的字段名和值是否符合预期:
console.log('查询结果示例:', flatResults[0]); // 输出示例:{ category_id: 1, category_name: '前端开发', skill_id: 2, ... }
内容的提问来源于stack exchange,提问作者LautaroColella
相关产品推荐
相关产品推荐

