Sequelize 如何构建应用程序的聊天部分?

Sequelize how to structure the chat part of the app?

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

我有一个 posts 模型和一个用户模型。每个用户可以 post 任意数量的 post,但每个 post 只属于一个用户。

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); 
};

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

我的联想和 table 结构是否正确?

更新

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'
});

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

这是我的 post 请求:

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);

});

所有模型看起来都不错。问题与协会有关。

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

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 处理)。