Reputation: 11
I am trying to build a web chat application that uses express, sequelize and mysql. My logic is that a user belongs to many chats and that a chat belongs to many users. I have created a junction table for this association called User_chat
. I have only recently learned about sequelize and am still coming to grips with the logic. I have a simple get request:
router.get('/', withAuth, async (req, res) => {
try {
const userChatRooms = await Chat.findAll({
include: [{ model: User_chat }]
});
console.log(userChatRooms);
res.json(userChatRooms);
} catch (e) {
console.log(e);
res.status(500).json(e);
}
});
which always returns the following error:
EagerLoadingError [SequelizeEagerLoadingError]: User_chat is not associated to Chat!
at Function._getIncludedAssociation (/Users/nem/Desktop/proj/chat/node_modules/sequelize/lib/model.js:710:13)
at Function._validateIncludedElement (/Users/nem/Desktop/proj/chat/node_modules/sequelize/lib/model.js:614:53)
at /Users/nem/Desktop/proj/chat/node_modules/sequelize/lib/model.js:509:37
at Array.map (<anonymous>)
at Function._validateIncludedElements (/Users/nem/Desktop/proj/chat/node_modules/sequelize/lib/model.js:504:39)
at Function.findAll (/Users/nem/Desktop/proj/chat/node_modules/sequelize/lib/model.js:1723:12)
at async /Users/nem/Desktop/proj/chat/controllers/api/chat-routes.js:8:27
I would like to be able to return the chat_name
of the user logged in. The query i had in mind is:
select c.email, a.chat_name from chat a
left join user_chat b on a.chat_id = b.chat_id
left join user c on b.user_id = c.user_id
where c.user_id = 1;
My association table is shown below:
const { Chat } = require('./Chat');
const { User } = require('./User');
const { User_chat } = require('./User_chat');
const { Message } = require('./Message');
// Defining associations between the models
//TODO: Define between user and chat - many to many
//Junction table is user_chat
Chat.belongsToMany(User, { through: 'User_chat' });
//TODO: Define between chat and user - many to many
//Junction table is user_chat
User.belongsToMany(Chat, { through: 'User_chat' });
//TODO: Define between user and message - one to many
User.hasMany(Message, {
foreignKey: 'sender_id',
onDelete: 'CASCADE'
});
//TODO: Define between chat and message - one to many
Chat.hasMany(Message, {
foreignKey: 'chat_id',
onDelete: 'CASCADE'
});
//TODO: Define between message and chat - one to one
Message.belongsTo(Chat, {
foreignKey: 'chat_id'
});
//TODO: Define between message and user - one to one
Message.belongsTo(User, {
foreignKey: 'sender_id'
});
module.exports = {
Chat,
User,
User_chat,
Message
};
Model Design
const { Model, DataTypes } = require('sequelize');
const bcrypt = require('bcryptjs');
const sequelize = require('../config/connection.js');
class User extends Model {
checkPassword(userLoginPassword) {
return bcrypt.compareSync(userLoginPassword, this.password);
}
}
User.init(
//TODO: Define the model for users
{
user_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
username: {
type: DataTypes.STRING(30),
allowNull: false,
unique: true
},
email: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING(255),
allowNull: false
}
},
{
hooks: {
async beforeCreate(newUserData) {
newUserData.password = await bcrypt.hash(newUserData.password, 10);
return newUserData;
}
// async beforeUpdate(updatedUserData) {
// updatedUserData.password = await bcrypt.hash(
// updatedUserData.password,
// 10
// );
// return updatedUserData;
// }
},
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true
}
);
module.exports = { User };
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/connection.js');
class Chat extends Model {}
Chat.init(
//TODO: Define the model for chats
{
chat_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
chat_name: {
type: DataTypes.STRING(255),
unique: true,
allowNull: false
}
},
{
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true
}
);
module.exports = { Chat };
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/connection.js');
class User_chat extends Model {}
User_chat.init(
//Junction table for the user and chat id since it will be many to many.
{
user_id: {
type: DataTypes.INTEGER
references: {
model: 'User',
key: 'user_id'
}
},
chat_id: {
type: DataTypes.INTEGER
references: {
model: 'Chat',
key: 'chat_id'
}
},
is_owner: {
type: DataTypes.BOOLEAN
}
},
{
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true
}
);
module.exports = { User_chat };
const { Model, DataTypes, literal } = require('sequelize');
const sequelize = require('../config/connection.js');
class Message extends Model {}
Message.init(
//TODO: Define the model for message
{
message_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
message_content: {
type: DataTypes.STRING(255),
allowNull: false
},
chat_id: {
type: DataTypes.INTEGER,
references: {
model: 'chat',
key: 'chat_id'
}
},
sender_id: {
type: DataTypes.INTEGER,
references: {
model: 'user',
key: 'user_id'
}
}
// created_at: {
// type: 'TIMESTAMP',
// defaultValue: literal('CURRENT_TIMESTAMP'),
// allowNull: false
// }
},
{
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true
}
);
module.exports = { Message };
Upvotes: 0
Views: 1343
Reputation: 22813
If you wish to get all user's chats then indicate User
model in include
and not the junction model. Moreover it's easier to start a query with a user because you wish to add a condition for it:
const userWithChats = await User.findAll({
where: {
user_id: 1
},
attributes: ['email'],
include: [{
model: Chat,
attributes: ['chat_name']
}]
});
const chats = userWithChats.Chats
Upvotes: 1