如何通过连接表查询Sequelize模型?使用through:model时报错
Sequelize多对多关联查询报错:TypeError: Cannot read properties of undefined (reading 'getTableName')
问题背景
开发练习用Web应用,单模型查询数据库正常,但通过连接表实现多对多关联查询时出错,需求是获取指定用户加入的所有聊天会话。
执行的查询代码
const models = require('../db/models'); // 在API接口内 const userChats = await models.User.findOne({ where: { id: req.user.id }, include: [ { model: models.Chat, through: models.User_Chat } ] });
报错信息
C:\...mypath...\node_modules\sequelize\lib\dialects\abstract\query-generator.js:1376 const throughTable = through.model.getTableName(); ^ TypeError: Cannot read properties of undefined (reading 'getTableName')
相关模型定义
Chat模型
const { sq } = require("../config/db"); const { DataTypes } = require('sequelize'); const Chat = sq.define('Chat', { id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4, allowNull: false }, name: { type: DataTypes.STRING, allowNull: false } }, { tableName: 'chats', timestamps: true, }); Chat.associate = (models) => { Chat.belongsToMany(models.User, { through: models.User_Chat, foreignKey: 'chat_id', otherKey: 'user_id' }); Chat.hasMany(models.Message, { foreignKey: 'chat_id'}); Chat.belongsTo(models.User, { foreignKey: 'creator_id'}); }; module.exports = { Chat };
User模型
const { sq } = require("../config/db"); const { DataTypes, Sequelize } = require('sequelize'); const User = sq.define("User", { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, allowNull: false, }, email: { type: DataTypes.STRING, allowNull: false, validate: { is: /^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$/ }, unique: true }, password: { type: DataTypes.STRING, allowNull: false, }, }, { tableName: 'users' }); User.associate = (models) => { User.belongsToMany(models.Chat, { through: models.User_Chat, foreignKey: 'user_id', otherKey: 'chat_id' }); User.hasMany(models.Message, { foreignKey: 'sender_id' }); User.hasMany(models.Chat, { foreignKey: 'creator_id' }); }; module.exports = { User }
User_Chat连接表模型
const { sq } = require("../../config/db"); const { DataTypes, Sequelize } = require('sequelize'); const User_Chat = sq.define('User_Chat', { user_id: { type: DataTypes.UUID, allowNull: false }, chat_id: { type: DataTypes.UUID, allowNull: false } }, { tableName: 'users_chats' }); module.exports = { User_Chat }
模型初始化代码
// Imported models const UserModel = require('./user').User; const ChatModel = require('./chat').Chat; const MessageModel = require('./message').Message; // Imported junction model(s) const User_ChatModel = require('./junctions/user_chat').User_Chat; // Initialize models const models = { User: UserModel, Chat: ChatModel, Message: MessageModel, User_Chat: User_ChatModel }; console.log('\n model index running \n'); // Apply associations Object.keys(models).forEach(modelName => { console.log('\nmodel name:', modelName, 'associating'); if (models[modelName].associate) { models[modelName].associate(models); } }); module.exports = models;
问题分析与解决方案
核心错误原因
在include配置中手动指定through: models.User_Chat是多余且不符合语法要求的。你已经在User.belongsToMany(models.Chat)和Chat.belongsToMany(models.User)的关联定义中指定了连接表,Sequelize会自动复用这个配置。手动传入模型对象作为through值,会导致Sequelize内部无法正确解析连接表元数据,从而抛出cannot read getTableName错误。
修复步骤
- 简化查询代码:去掉
include中的through配置,直接关联models.Chat即可:
const userChats = await models.User.findOne({ where: { id: req.user.id }, include: [models.Chat] });
- 规范连接表定义(可选但推荐):为连接表的复合字段添加主键标识,让Sequelize更清晰识别关联关系:
const User_Chat = sq.define('User_Chat', { user_id: { type: DataTypes.UUID, allowNull: false, primaryKey: true // 标记为主键 }, chat_id: { type: DataTypes.UUID, allowNull: false, primaryKey: true // 标记为主键 } }, { tableName: 'users_chats', timestamps: false // 不需要 createdAt/updatedAt 可关闭,避免冗余字段 });
- 验证关联初始化:当前模型初始化代码已正确遍历执行所有
associate方法,确保关联关系加载正常,无需修改。
预期结果
修复后,Sequelize会自动通过users_chats表关联users.id与users_chats.user_id、chats.id与users_chats.chat_id,返回包含该用户及所属所有聊天会话的完整数据。
内容的提问来源于stack exchange,提问作者PandaBearTellEm
相关产品推荐
相关产品推荐

