Node.js+Sequelize项目调用Model.create/build报is not a function求助
问题根源
你遇到的是Node.js CommonJS模块规范下的循环依赖问题:user.js顶部引入了token.js,token.js顶部又引入了user.js,模块加载到一半时会返回未完成初始化的模块副本,所以你在user.js中拿到的Token不是完整的Sequelize模型实例,自然不存在create/build等方法,同时sequelize.models中也还未完成Token模型的注册。
解决方案
规范解法:抽离关联定义(推荐)
Sequelize官方推荐将模型关联定义统一放在所有模型加载完成后执行,避免跨模型引用:
- 清理两个模型文件的互相依赖和关联代码:
- 删除
models/user.js顶部的const Token = require('./token')语句 - 删除
models/token.js顶部的const User = require('./user')语句,以及两个文件中写的hasMany/belongsTo关联代码
- 在你的Sequelize初始化文件(即代码中引入的
../db/sequelize文件)末尾统一注册关联:
// 引入所有已定义的模型 const User = require('../models/user') const Token = require('../models/token') // 统一定义关联关系 User.hasMany(Token, { as: 'tokens' }) Token.belongsTo(User, { foreignKey: 'UserId', as: 'user' }) // 可将模型挂载到db对象上方便全局调用 db.User = User db.Token = Token
- 修复
user.js中gAuth方法的问题:
User.gAuth = async function(user) { const token = jwt.sign({id: user.id.toString() }, 'password', { expiresIn: '7 days' }) // 从sequelize实例直接获取已注册的Token模型,无需单独引入 const newToken = await sequelize.models.Token.create({ token, UserId: user.id // 此处外键要和你定义的字段名一致,原代码的this.id指向错误,静态方法this为User模型本身而非实例 }) // create方法已自动执行保存,无需额外调用save() return token }
临时解法:动态引入(仅用于快速验证)
不需要改结构,直接把user.js顶部的const Token = require('./token')移动到gAuth方法内部即可,运行时模块已经加载完成,不会出现循环依赖问题。
内容的提问来源于stack exchange,提问作者Joshua Fleuri
相关产品推荐
相关产品推荐

