【问题标题】:Sequelize how to structure the chat part of the app?Sequelize 如何构建应用程序的聊天部分?
【发布时间】:2021-03-17 22:57:15
【问题描述】:

我目前有一个应用程序,用户可以在其中登录并发布帖子。每个帖子旁边都有一个按钮,如果按下该按钮,当前用户可以向创建帖子的用户发送消息。

我有一个帖子模型和一个用户模型。每个用户可以发布任意数量的帖子,但每个帖子只属于一个用户。

const User = db.define(
"User",
{
id: {
  type: Sequelize.INTEGER,
  primaryKey: true,
  autoIncrement: true,
},
name: {
  type: Sequelize.STRING,
  },
email: {
  type: Sequelize.STRING,
},
password: {
  type: Sequelize.STRING,
},
},
);

const Post = db.define(
"Post",
{
id: {
  type: Sequelize.INTEGER,
  primaryKey: true,
  autoIncrement: true,
},
title: {
  type: Sequelize.STRING,
},
subTitle: {
  type: Sequelize.STRING,
},
userId: {
  type: Sequelize.INTEGER,
},
},
);

User.hasMany(Post,
{ foreignKey: "userId" }
);

Post.belongsTo(User, 
{ foreignKey: "userId" }
);

我现在要实现的是消息传递功能。

到目前为止,这是我的消息模型:

  const Messages = db.define("Messages", {
  id: {
  allowNull: false,
  autoIncrement: true,
  primaryKey: true,
  type: Sequelize.INTEGER,
  },
 senderId: {
 type: Sequelize.STRING,
 },
 receiverId: {
 type: Sequelize.STRING,
 },
 message: {
 type: Sequelize.STRING,
 },
});

User.hasMany(Messages, {
foreignKey: 'senderId'
});

User.hasMany(Messages, {
foreignKey: 'receiverId'
});

Messages.associate = (models) => {
Messages.belongsTo(models.Post, {
foreignKey: "PostId",
});
Messages.belongsTo(models.User, {
foreignKey: "senderId",
});
Messages.belongsTo(models.User, {
foreignKey: "receiverId",
});
};

User.hasMany(Conversations, {
foreignKey: 'conversationId'
});

到目前为止,这是我的对话模型:

const Conversations = db.define("Conversations", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
}
});

module.exports = Conversations;

Conversations.associate = (models) => {
Conversations.hasMany(models.Message); 
models.Message.belongsTo(Conversations); 
};

此外,消息可以从一个用户发送给另一个用户,而不是一组用户。

我的关联和表结构是否正确?

更新

User.hasMany(Messages, {
foreignKey: 'senderId'
});

User.hasMany(Messages, {
foreignKey: 'receiverId'
});

Messages.associate = (models) => {
Messages.belongsTo(models.User, {
foreignKey: "senderId",
});
Messages.belongsTo(models.User, {
foreignKey: "receiverId",
});
Messages.belongsTo(models.Conversations,{
foreignKey: "conversationId",
});
};

Conversations.associate = (models) => {
Conversations.hasMany(models.Messages,{
  foreignKey: "conversationId",
}); 
Conversations.belongsTo(models.Post,{
  foreignKey: "PostId",
})
};

Post.hasMany(Conversations, { foreignKey: "PostId" });

User.hasMany(Conversations, {
foreignKey: 'user1'
});

User.hasMany(Conversations, {
foreignKey: 'user2'
});

当我尝试发送消息时使用此实现,消息表中的 conversationId 为空。

这是我的发帖请求:

router.post("/", 
auth, 
async (req, res) => {

const post = await Post.findOne({where:{id:req.body.postId}})
if (!post) return res.status(400).send({ error: "Invalid postId." });

const targetUser = await User.findOne({where:{post.userId}})
if (!targetUser) return res.status(400).send({ error: "Invalid 
userId." });

await Conversations.findOne({
where:{
  user1:{[Op.or]:[req.user.id,post.userId]},
  user2:{[Op.or]:[req.user.id,post.userId]},
  PostId:req.body.postId,
}
}).then(conversation=>{
if(conversation){
  return conversation
}else{
  return Conversations.create({
    user1: req.user.id,
    user2: post.userId,
    PostId:req.body.postId,
  })
}
}
)
  Messages.create({
  senderId: req.user.id,
  receiverId: post.userId,
  message: req.body.message,
  conversationId:conversation.id //MY PROBLEM IS HERE
})
.then(
  res.status(201).send({
    msg: "upload successful",
  }));

const { expoPushToken } = targetUser;

if (Expo.isExpoPushToken(expoPushToken))
await sendPushNotification(expoPushToken, message);

});

【问题讨论】:

  • 对话可以完全不与帖子相关吗?它们可以在任意两个用户之间吗?
  • 实际上是的,对话将与帖子相关(但相同的用户可以就不同的帖子进行不同的对话)。是的,只有 2 个用户之间的对话。

标签: postgresql sequelize.js


【解决方案1】:

所有型号看起来都不错。问题在于关联。

如果您在相同的两个模型之间定义了多个关联,则应指明不同的别名以在查询中将它们彼此区分开。

User.hasMany(Messages, {
foreignKey: 'senderId',
as: 'OutgoingMessages'
});

User.hasMany(Messages, {
foreignKey: 'receiverId',
as: 'IncomingMessages'
});
Messages.belongsTo(models.User, {
foreignKey: "senderId",
as: 'Sender'
});
Messages.belongsTo(models.User, {
foreignKey: "receiverId",
as: 'Receiver'
});

另外,最好在模型定义之后直接以相同的方式定义关联,或者在associate 等静态方法中定义关联。后一种方法更可取,因为它允许在其自己的模块中定义每个模型,而无需使用associate 方法中的models 参数来访问应与给定模型关联的其他模型。

最后一点:尝试定义关联,其中关联定义左侧的模型在其自己的associate 方法中。 这意味着

models.Message.belongsTo(Conversations);

应该在Message模型associate方法中:

Message.belongsTo(models.Conversations);

这样,您始终知道在哪里可以找到定义从某个模型到其他模型的链接的所有关联。

更新

您应该将找到或创建的对话存储到一个变量中,以便在创建消息时使用它:

let conversation = await Conversations.findOne({
  where:{
    user1:{[Op.or]:[req.user.id,post.userId]},
    user2:{[Op.or]:[req.user.id,post.userId]},
    PostId:req.body.postId,
  }
})

if (!conversation){
  conversation = await Conversations.create({
    user1: req.user.id,
    user2: post.userId,
    PostId:req.body.postId,
  })
}
const newMessage = await Messages.create({
  senderId: req.user.id,
  receiverId: post.userId,
  message: req.body.message,
  conversationId:conversation.id
})
res.status(201).send({
  msg: "upload successful",
});

不要试图混淆then/catchawait。如果您使用await,您将已经有结果或异常(您可以使用try/catch 处理)。

【讨论】:

  • 是的,如果对话总是链接到某个帖子,那么 postId 应该在 Conversation 模型中,而不是在 Message 模型中
  • 是的,将conversationId 添加到Messages
  • 是的,像这样。但这对你来说是一堆全新的问题和答案,所以祝你好运!
  • 是的,有两条路线似乎合乎逻辑:1. 创建一个对话(连同一条消息) 2. 在现有对话中创建一条消息
  • 如果您收到所有对话消息,那么是的,您可以使用 OR 添加有关 senderId 和 receiverId 的条件
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-07
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
相关资源
最近更新 更多