Sequelize报错Model.getAttributes is not a function的排查咨询
问题:Sequelize模型
getAttributes()调用随机报错 背景
拥有对象数组docs和用于构建对象的Sequelize模型model,处理流程如下:
let mappedChunk = await Promise.all( docs.map(async (item) => { const pg_item: any = await model.build({ _pg_key: uuidv4(), _source: JSON.stringify(item), }).dataValues await baseMapping(item, pg_item) if (extraMapping) { const status = await extraMapping(item, pg_item) } return pg_item }), ) await model.bulkCreate(mappedChunk, bulkCreateOptions)
baseMapping和extraMapping用于将数组对象属性映射到Sequelize模型对应属性,这部分逻辑正常,对象可成功转为pg_items。
问题场景
处理一对多/多对多关联时,检查模型是否存在指定外键的代码如下:
const Model = pg_item.constructor if (!(foreignKeyName in Model.getAttributes())) {...}
程序随机报错:"Model.getAttributes is not a function",日志显示Model为原生Object构造函数:
pg_item <--------- [object Object] Model <--------- function Object() { [native code] } ... TypeError: Model.getAttributes is not a function at /home/ulkash/Desktop/Cloned/mgn-sequelize/build/seeders/scripts/utils/relationsBinding.js:26:49 at Generator.next (<anonymous>)
排查方向与解决建议
1. 根源分析
model.build().dataValues返回的是纯JavaScript对象,而非Sequelize模型实例。虽然多数情况下constructor会指向Sequelize模型,但如果baseMapping或extraMapping中存在修改pg_item原型、重新赋值对象,或者使用Object.assign/解构等操作覆盖了原对象的原型链,就会导致pg_item.constructor变回原生Object。
2. 具体解决方法
方法一:保留Sequelize实例,不直接取dataValues
不要直接提取dataValues,而是先保留模型实例,操作完成后再取dataValues用于批量创建:
docs.map(async (item) => { // 保留模型实例,不直接取dataValues const pg_instance = await model.build({ _pg_key: uuidv4(), _source: JSON.stringify(item), }) // 直接操作实例的dataValues(或直接操作实例属性) await baseMapping(item, pg_instance.dataValues) if (extraMapping) { await extraMapping(item, pg_instance.dataValues) } // 后续检查模型时直接用pg_instance.constructor const Model = pg_instance.constructor if (!(foreignKeyName in Model.getAttributes())) { // 逻辑处理 } // 最后返回dataValues用于bulkCreate return pg_instance.dataValues })
方法二:手动绑定模型引用
如果必须直接使用dataValues对象,可以在创建时手动给pg_item添加模型引用属性,避免依赖原型链:
const pg_item: any = await model.build({ _pg_key: uuidv4(), _source: JSON.stringify(item), }).dataValues // 手动挂载模型引用 pg_item._model = model
后续检查时直接使用这个引用:
if (!(foreignKeyName in pg_item._model.getAttributes())) {...}
方法三:排查映射函数中的对象修改
检查baseMapping和extraMapping函数,确认是否存在以下操作:
- 使用
Object.assign({}, pg_item)创建新对象并覆盖原pg_item - 对
pg_item进行解构后重新赋值 - 修改
pg_item的__proto__属性
这些操作会破坏原对象的原型链,导致constructor指向原生Object。
内容的提问来源于stack exchange,提问作者uli
相关产品推荐
相关产品推荐

