Sequelize外键关联问题:如何将关联字段展平为顶层属性
解决方案
咱们一步步来解决你的问题,先理清楚关联关系的合理性,再调整查询结构得到你想要的返回格式:
1. 修正关联关系(更符合业务逻辑)
你当前用hasOne关联skillsets和ratings,但从业务场景看,一个技能应该可以对应多个员工的评分(不同empID的ratings记录),所以更合适的关联是hasMany而非hasOne。同时检查字段映射是否匹配:
// 修正后的关联定义 skillsets.hasMany(ratings, { foreignKey: 'skillID', sourceKey: 'skillsetID' // 确保skillsets模型的skillsetID对应数据库的skill_id字段 }); ratings.belongsTo(skillsets, { foreignKey: 'skillID', targetKey: 'skillsetID' });
如果你的业务确实是一个技能对应某员工的唯一评分,hasOne也能运行,但hasMany更通用,不会限制后续扩展。
2. 调整查询得到期望的返回格式
现在返回的rating是嵌套对象,要直接变成数值,有两种实用方案:
方案一:通过Sequelize查询直接映射字段
在findAll中,直接将关联表的rating字段映射为主模型的属性,同时隐藏关联模型的冗余属性,并开启raw: true返回平面对象:
const result = await skillsets.findAll({ where: { roleID: role }, attributes: [ 'skillsetID', 'roleID', 'field', 'skillName', // 把关联表的rating字段映射为当前对象的rating属性 [sequelize.col('rating.rating'), 'rating'] ], include: [{ model: ratings, where: { empID: empID }, // 这里用模型属性名empID,而非数据库字段emp_id,更符合规范 attributes: [], // 不返回关联模型的其他属性 required: false }], raw: true // 返回平面对象,而非Sequelize模型实例 });
这样生成的SQL会直接把rating.rating作为rating列返回,结果就是你期望的结构,rating是数值类型。
方案二:查询后手动转换结果格式
如果不想修改查询结构,可以在查询完成后,用map函数调整返回格式:
const results = await skillsets.findAll({ where: { roleID: role }, include: [{ model: ratings, where: { empID: empID }, attributes: ['rating'], required: false }] }); // 转换为目标格式 const formattedResults = results.map(item => { // 先把模型实例转为普通对象 const plainItem = item.get({ plain: true }); return { ...plainItem, // 有评分则取数值,否则设为null,parseInt转换为数字类型 rating: plainItem.rating ? parseInt(plainItem.rating.rating) : null }; });
额外小提示
你查询里的where:{ emp_id: empID }建议改成where:{ empID: empID },因为模型里的属性名是empID(对应数据库字段emp_id),用模型属性名更符合Sequelize的设计规范,避免硬编码数据库字段名。
内容的提问来源于stack exchange,提问作者Gayathri
相关产品推荐
相关产品推荐

