问题
I am trying to get the conversations of each user to show them on my inbox screen in my front-end. I am able to post messages to the database, but when I try to getting them, I keep getting
[SequelizeEagerLoadingError]: Message is not associated to Conversation!
Can someone please have a look at my code.
Here is my get request:
router.get('/', auth, (req, res) => {
Conversation.findAll({
where: {
[Op.or]: [
{
user1: { [Op.eq]: req.user.id },
user2: { [Op.eq]: req.user.id },
},
],
},
include: [{ model: Message }],
})
.then(() => res.send())
.catch((err) => console.log(err));
});
Here is my Conversation Model
const Conversation = db.define('Conversation', {
});
module.exports = Conversations;
Conversation.associate = (models) => {
Conversation.hasMany(models.Message, {
foreignKey: 'conversationId',
});
Conversation.belongsTo(models.Post, {
foreignKey: 'PostId',
});
};
User.hasMany(Conversation, {
foreignKey: 'user1',
});
User.hasMany(Conversation, {
foreignKey: 'user2',
});
Here is my Message model:
const Message = db.define('Message', {
id: {
primaryKey: true,
type: Sequelize.INTEGER,
},
senderId: {
type: Sequelize.STRING,
},
receiverId: {
type: Sequelize.STRING,
},
message: {
type: Sequelize.STRING,
},
conversationId: {
type: Sequelize.INTEGER,
},
});
module.exports = Message;
User.hasMany(Message, {
foreignKey: 'senderId',
as: 'SentMessage',
});
User.hasMany(Message, {
foreignKey: 'receiverId',
as: 'ReceivedMessage',
});
Message.associate = (models) => {
Message.belongsTo(models.User, {
foreignKey: 'senderId',
as: 'Sender',
});
Message.belongsTo(models.User, {
foreignKey: 'receiverId',
as: 'Receiver',
});
Message.belongsTo(models.Conversation, {
foreignKey: 'conversationId',
});
};
Post.hasMany(Conversation, { foreignKey: 'PostId' });
Update
After removing
Conversation.hasMany(models.Message,{foreginKey:"conversationId"})
from my associate method in my Conversation Model and adding it into my Message model i stopped getting the association error, but now when i try testing the get request i keep getting an empty response while my database is full of entries.
Here is my updated get request:
router.get('/',auth,async(req,res)=>{
const conversation = await Conversations.findAll({
include:[{
model:Message,
required: false,
}],
where:{
[Op.or]:[{
user1:{[Op.eq]:req.user.id},
user2:{[Op.eq]:req.user.id},
}]
},
});
if(!conversation) return res.send().catch(err=>console.log(err))
res.status(200).send()
})
Here is my response in the terminal:
Executing (default): SELECT "Conversation"."id",
"Conversation"."createdAt", "Conversation"."updatedAt",
"Conversation"."user1", "Conversation"."user2",
"Conversation"."PostId", "Messages"."id" AS "Messages.id",
"Messages"."senderId" AS "Messages.senderId",
"Messages"."receiverId" AS
"Messages.receiverId",
"Messages"."message" AS "Messages.message",
"Messages"."conversationId" AS "Messages.conversationId",
"Messages"."createdAt" AS "Messages.createdAt",
"Messages"."updatedAt" AS "Messages.updatedAt" FROM "Conversations"
AS "Conversation" LEFT OUTER
JOIN "Messages" AS "Messages" ON "Conversation"."id" =
"Messages"."conversationId" WHERE (("Conversation"."user1" = 43 AND
"Conversation"."user2" = 43));
回答1:
const { user } = require("./containers/api/config/database")
There a few improvements you can make - the issue in your example code is that you have multiple relationships between Messages
and User
so you ned to specify the as
keyword so Sequelize knows which to use. You don't have any without the as
in the association so as far as Sequelize can tell there is no relationship.
I would let Sequelize generate most of the columns automatically for primary and foreign keys to keep things simple. It's also good practice to use singular table names and let Sequelize pluralize them when multiple results can be returned, like Post.getConversations()
vs Message.getConversation()
. It's also more readable to use async/await
instead of thenables if you can.
You should be able to move the where
to the Message
include and add required: true
to make it a RIGHT JOIN
.
Models
const User = db.define('user', {
// fields go here
});
const Post = db.define('post', {
// fields go here
});
const Conversation = db.define('conversation', {
// don't define columns, they will be generated
});
const Message = db.define('message', {
message: {
type: Sequelize.STRING,
},
// more fields
});
Associations
// Message -- Conversation, creates message.conversationId NOT NULL
Message.belongsTo(Conversation, { allowNull: false });
// Conversation -< Messages, uses message.conversationId
Conversation.hasMany(Message);
// Conversation -- User, creates conversation.creatorId NOT NULL
Conversation.belongsTo(User, { as: 'Creator', foreignKey: 'creatorId', allowNull: false });
// User -< Conversations, uses conversation.creatorId
User.hasMany(Conversation, { as: 'CreatedConversations', foreignKey: 'creatorId' });
// Message -- User, creates message.senderId NOT NULL
Message.belongsTo(User, { as: 'Sender', foreignKey: 'senderId', allowNull: false });
// User -< Message (Sent), join user.id = message.senderId
User.hasMany(Message, { as: 'Sent', foreignKey: 'senderId' });
// Message -- User, creates message.receiverId NOT NULL
Message.belongsTo(User, { as: 'Receiver', foreignKey: 'receiverId', allowNull: false });
// User -< Message (Received), join user.id = message.receiverId
User.hasMany(Message, { as: 'Received', foreignKey: 'receiverId' });
// Conversation -- Post, creates conversation.postId NOT NULL
Conversation.belongsTo(Post, { allowNull: false });
// Post -< Conversations, uses conversation.postId
Post.hasMany(Conversation);
Query Get all the conversations where the user is in the Messages as a sender or receiver.
router.get('/', auth, async (req, res) => {
try {
const conversations = await Conversation.findAll({
include: [{
model: Message,
where: {
[Op.or]: [
{ senderId: req.user.id },
{ receiverId: req.user.id },
],
},
required: true, // RIGHT JOIN
}],
});
return res.json(conversations);
} catch (err) {
console.log(err);
return res.status(500).send(err);
}
});
Query
Get all the conversations created by a user. This replaces the user1
and user2
on the conversation, but you may still want it for something else.
router.get('/created_conversations', auth, async (req, res) => {
try {
const conversations = await Conversation.findAll({
include: [{
model: Message,
required: false, // LEFT JOIN
}],
where: {
creatorId: req.user.id
},
});
return res.json(conversations);
} catch (err) {
console.log(err);
return res.status(500).send(err);
}
});
router.get('/user', auth, async (req, res) => {
try {
const user = await User.findByPk(req.user.id, {
include: [{
model: Conversation,
as: 'CreatedConversations',
required: false, // LEFT JOIN
include: [{
model: Message,
required: false, // LEFT JOIN
}],
}],
});
// const conversations = user.getConversations();
// const [conversation] = conversations; // get the first result
// const messages = conversation.getMessages();
return res.json(user);
} catch (err) {
console.log(err);
return res.status(500).send(err);
}
});
回答2:
after many days of trying to solve this problem and with the help of Anatoly and doublesharp and i finally figured out how.
My problem was my associate method inside my Conversation Model was not getting executed for some reason i still do not know, so i removed it from my associate method inside my conversation model and added it inside my messages model and it worked.
Here is my code:
Message Model:
const Message = db.define("Message", {
senderId: {
type: Sequelize.STRING,
},
receiverId: {
type: Sequelize.STRING,
},
message: {
type: Sequelize.STRING,
},
conversationId:{
type: Sequelize.INTEGER,
}
});
module.exports = Message;
User.hasMany(Message, {
as:"SentMessage",
foreignKey: 'senderId',
});
User.hasMany(Message, {
as:"ReceivedMessage",
foreignKey: 'receiverId',
});
Message.associate = (models) => {
Message.belongsTo(models.User, {
as:"Sender",
foreignKey: "senderId",
allowNull: false
});
Message.belongsTo(models.User, {
as:"Receiver",
foreignKey: "receiverId",
allowNull: false
});
Message.belongsTo(models.Conversations, { allowNull: false },{
foreignKey: "conversationId",
}
};
Conversation.hasMany(Message,{
foreignKey: "conversationId",
}
);
Here is my Conversation model:
const Conversation = db.define("Conversation", {});
module.exports = Conversation;
User.hasMany(Conversation, {
foreignKey: 'user1'
});
User.hasMany(Conversation, {
foreignKey: 'user2'
});
Conversation.belongsTo(User, { as: 'Creator', foreignKey: 'user1', allowNull:
false })
Conversation.belongsTo(User, { as: 'Recipient', foreignKey: 'user2',
allowNull: false })
Here is my Post Model associations:
Post.hasMany(Conversation, { foreignKey: "PostId" });
Conversation.belongsTo(Post,{
foreignKey: "PostId",
allowNull: false
})
Here is my GET request:
router.get('/', auth, async (req, res) => {
try {
const conversations = await Conversation.findAll({
include: [{
model: Message,
where: {
[Op.or]: [
{ senderId: req.user.id },
{ receiverId: req.user.id },
],
},
required: true, // RIGHT JOIN
}],
});
return res.json(conversations);
} catch (err) {
console.log(err);
return res.status(500).send(err);
}
});
Here is my Postman Response:
[
{
"id": 1,
"user1": 43,
"user2": 45,
"PostId": 523,
"Messages": [
{
"id": 1,
"senderId": 43,
"receiverId": 45,
"message": "My first message & Conversation",
"conversationId": 1,
}
]
},
{
"id": 4,
"user1": 43,
"user2": 45,
"PostId": 522,
"Messages": [
{
"id": 7,
"senderId": 43,
"receiverId": 45,
"message": "One more time",
"conversationId": 4,
},
]
},
{
"id": 5,
"user1": 45,
"user2": 43,
"PostId": 518,
"Messages": [
{
"id": 11,
"senderId": 45,
"receiverId": 43,
"message": "Hello 43",
"conversationId": 5,
}
]
}
]
来源:https://stackoverflow.com/questions/65179061/how-to-get-the-conversations-for-each-user-and-include-the-messages