聊天的数据库模式:私人和群组
Posted
技术标签:
【中文标题】聊天的数据库模式:私人和群组【英文标题】:Database schema for chat: private and group 【发布时间】:2018-03-11 03:10:52 【问题描述】:我正在尝试设计具有私人聊天和群聊功能的数据库架构。到目前为止,这是我所得到的:
所以 - 理论上,即使用户只是在一对一的私人聊天中,他们仍然被分配了一个“房间 ID”,并且他们发送的每条消息都是给那个 room
。
要找出他们所涉及的所有房间,我可以从participants
表中选择一个列表来查找。
这没关系,但是我觉得room
表有点多余,因为我真的不需要房间名称,我可以省略它并简单地使用participants
表和@ 987654327@了解各个房间。
谁能向我解释一个更好的结构或为什么我应该保留房间桌子?
【问题讨论】:
你有外键吗? @RyanGadsdon 是的,这些行表示外键 啊,我知道了,以前在名字旁边看到 FK :) 我会把私人房间和公共房间分开。或者使用私人和公共房间子类创建房间属性。我会保留空间,因为如果您有不同的聊天室会发生什么?例如运动、社交、工作。将人们链接到聊天室会更容易 @RyanGadsdon 为一对一聊天的群组命名。他们应该看到彼此的名字。 我认为一种解决方案可以同时使用用户的用户名,如john_mike
,并在发送任何一个时拆分它们。 mike
show john 和 john show mike
?
【参考方案1】:
我认为您可能需要稍微改进您的域模型 - 否则,很难说您的架构是否“正确”。
以 Slack 为模型(注意——我没有对此做大量研究,所以细节可能有误),你可能会说你的系统有“聊天”。
聊天可以是公开的 - 即所有用户都可以查看和加入 - 或私人 - 即不为所有用户列出,并且只能通过邀请才能使用。
公共聊天必须具有“名称”属性。私人聊天可能有也可能没有名字属性。
一个聊天可以有 2..n 个参与者。
默认情况下,所有 1-1 聊天都以私密状态开始。
可以将私人聊天更改为公共聊天。
在这种情况下,您具有继承/专业化关系 - “私人”和“公共”是“聊天”的子类型。
关系模型在处理继承方面是出了名的糟糕; SO上有很多relatedquestions。
【讨论】:
【参考方案2】:对于一个带有群组和私人聊天(两个成员)的简单聊天系统,我会更喜欢这样做。
另一种可能性是创建一个仅用于群组消息的表格和一个用于私人聊天的表格。 (为了避免组和消息表之间的 n:m 或者您将 n:m 用作功能而不是可能的错误/逻辑错误)。如果您想要更复杂的聊天系统,请查看 Neville Kuyt 的帖子。
希望能帮到你。
【讨论】:
您知道,对,传统上 N:M 关系是通过中间表完成的? :) 所以用户组(房间)正好是 OP 图片中的participants
表。 Message:group 与 message:post_by_user 是 1:N 关系。因此,除了 OP 的方案更容易理解这一事实之外,我认为您的回答和初始 OP 的图片没有区别【参考方案3】:
您的架构看起来非常好,您可能会看到其他人(包括今天的我自己)以前或多或少具有相同的结构(Storing messages of different chats in a single database table、Database schema for one-to-one and group chat、Creating a threaded private messaging system like facebook and gmail)。我真的很想指出,你的视觉表现是最好的,它很容易理解和遵循:)
总的来说,我认为即使您目前没有特定属性(可能是name
、posting_allowed
、type
(即,如果您不仅对私人消息和聊天重用类似的结构,而且对带有 cmets 的公共帖子重用类似的结构)等等。具有单个索引 ID 的单表应该非常快并且开销接近于零,但是它将允许扩展相当无需修改所有现有代码即可轻松实现(即有一天您决定在聊天中添加name
)。
将 roomID 逻辑“隐藏”在 participants
表中将不透明且效率不高(即当您需要查找聊天的下一个 ID 时),我不建议这样做。
【讨论】:
为一对一聊天的群组命名。他们应该看到彼此的名字。 我认为一种解决方案可以同时使用用户的用户名,如john_mike
,并在发送任何一个时拆分它们。 mike
show john 和 john show mike
?
@SujeetAgrahari 您可能希望让用户有机会以他们想要的任何方式命名他们的聊天(可能需要使用键 (chat_id, user_id) 分隔的chat_names
表)。如果没有特定名称(即您想显示默认值),则只需在数据库中保留 name
值为空/null 并在客户端上动态生成名称(如您所说,如果是 1:1 聊天,那么例如,显示合作伙伴的姓名)。 不要存储要在客户端拆分的神奇字符串
“如果是 1:1 聊天,则显示合作伙伴的名字”这就是问题所在。 A 应该看到 B,B 应该看到 A,就像在其他聊天应用程序中一样。我看到你的名字,你在聊天窗口中看到我的。我将如何用这个模式来实现它?对于群聊,假设 A、B 和 C 参与其中。 A 应该看到“B, C”,B 应该在他们的聊天窗口中看到“A, C”。
@SujeetAgrahari 所有这些都应该在客户端 IMO 上完成。 DB 结构允许您获取给定聊天 (SELECT userID FROM participants WHERE roomID=123
) 的所有参与者,然后只需在您的代码中处理参与者,而不是在数据库中。【参考方案4】:
我知道这在游戏中有点晚了,但我已经做了一些,而且我在消息表中总是有一个active type bool
col。万一有人说了什么,你可以隐藏它,但仍然保留它的记录。以及用户表中的user_auth
。有时我会在房间的桌子上放auth_required -> user.user_auth
,以防你想要在许多不和谐中进行平级对话,并且总是在消息栏里添加datetime
。这些是最低标准,因为如果你没有它们,你以后会后悔的..
【讨论】:
以上是关于聊天的数据库模式:私人和群组的主要内容,如果未能解决你的问题,请参考以下文章
在 PHP 上使用 Ratchet 和 WebSockets 进行私人和群聊
基于WebRTC开源框架的实时视频聊天项目,搭建私人实时通信服务