2011-06-21 45 views
31

我创建了一个线程消息系统,很像gmail和facebook,其中收件箱列出了显示主题,发件人姓名和最新邮件的时间戳的最新线索。创建一个线程式的私人消息系统,如Facebook和Gmail

这里是我的表是如何设置:

users: 
    user_id 
    user_name 

thread: 
    thread_id 
    title 
    to_id 
    to_keep 
    to_read 
    from_id 
    from_keep 
    date 

message: 
    message_id 
    thread_id 
    to_id 
    from_id 
    message_text 
    date 

当用户创建一个新的消息,我在做什么现在的问题是,它会在线程表一个新的线程,然后在新的消息消息表以及用户是否响应线程,它会复制线程表中的当前线程,除了它交换to_idfrom_id,然后基于此创建新消息。

此外,对于收件箱视图,我只能根据user_id查询所有线程。所以类似SELECT * FROM thread WHERE to_id = 2 and to_keep = TRUE ORDER BY date DESC或者如果我想查看发件箱中的邮件,它会是类似于SELECT * FROM thread WHERE from_id = 2 and from_keep = TRUE ORDER BY date DESC

如果用户在有新消息时打开线程,则to_read更新为真UPDATE thread SET to_read = TRUE WHERE thread_id = 4

我觉得我已经结束了这个过程,并且应该有更好的方法来做到这一点。

任何帮助或想法,将不胜感激。

这样,我们只需从线程表中选择所有内容,然后与用户表进行连接即可显示我需要的所有内容。不过,我觉得应该有更好的方式来做到这一点。

+3

为什么线程需要to_id和from_id?消息是将发送者和接收者结合在一起的东西。线程只是消息的容器。或者我误解了? –

+0

不,你是对的。我只是在查询时选择了应该在收件箱中的所有线程,并且仅仅从线程中最近的消息中获取信息。那有意义吗? – bigmike7801

回答

45

为什么不从用户的每个消息的视图中分离出消息关系?

我会通过消息上的自引用关系来执行线程。换句话说,该消息具有“respond_to_message_id”列。

我不确定我明白你为什么有“to_id”。消息是否指向个人用户?这似乎非常有限。我认为你或者没有收件人(即收件人是任何人都可以阅读的留言板),或者你可以指定多个收件人,就像电子邮件一样。也许你可以更多地解释如何使用系统。

为了简单起见,假设您要发布到开发板,所以只有“from”很重要,那么您的消息表中有线程的自引用关系,用户表和交叉表在用户和消息之间存储哪些消息已被每个用户读取。

这样,如果您想知道用户是否读取了消息,只需尝试读取给定消息的交集表中的用户ID。如果它在那里不是,则该消息未被该用户读取。

请注意,如果您希望单个收件人拥有此设计,并且您希望拥有多个收件人,则可以使用交集表来保存每封邮件的收件人列表。如果你有一个收件人交叉表,它可以作为你的阅读状态表执行双重任务。

编辑:ERD素描:

这里是我谈论的速写...

ERD Sketch

无论发送者已经选择了保持所述消息被标记上的消息本身。如果消息是新线程的开始,则reply_to_message_id列为NULL,否则为父消息的message_id。可以有多个收件人,每个收件人都有自己的保留信息的能力,以及跟踪收件人阅读邮件的日期和时间的能力。

编辑2:备用ERD和查询最新的信息

@OP询问如何查询在一个线程中最近的消息。答案取决于线程的形式。你可以有一个扁平的线程,每个消息到达消息的线性流的末尾,或者你可以有一个树形线程,每个消息都有一个特定的父对象,除非它是线程的根。在上面的ERD中,可以使用reply_to_message_id字段。如果线程是平的,那么FK总是以根MESSAGE为根。如果线程是树形的,那么FK就是回复MESSAGE的直接父节点。

如果您想要运行的典型查询是“线程中最近的消息是什么?”和你的线程是平的,那么你可以使用SQL这样的:

select top 1 
    M.message_id 
, M.sent_datetime 
, M.title 
, M.message_text 
, S.user_id 
, S.user_name 
-- and anything else you want... 
from MESSAGE M inner join USER S 
    on M.sender_user_id = U.user_id 
where M.reply_to_message_id = @ThreadRootMessageID 
order by 
    M.sent_datetime desc 

如果,另一方面,你的线程是树形,这是你要能够快速,轻松地运行一个查询,那么上面ERD中的模式不是很容易处理。 SQL不擅长树。你可以通过一些非规范化来解决问题。请参阅下面的ERD:

Tree Thread ERD

注意,现在有一个FK展现眼前的父母和一个FK显示根。由于线程不会被编辑 - 至少要修改消息的根目录指向另一个线程的编辑,所需的非规范化并不意味着更新异常的风险,因此冗余不会太成问题。

如果使用此ERD,那么对于“线程X中最新消息”的查询与上述内容相同,但是在where子句中使用M.thread_root_message_id而不是M.reply_to_message_id。

+0

嗨,乔尔,你介意告诉我你将如何设置你的桌子,我不是很追随你如何去做。谢谢! – bigmike7801

+0

我很感谢你的贡献,但是我看不出如何创建一个线程消息。例如,对于1个线程可以有5条消息和4条消息。那有意义吗? – bigmike7801

+1

消息ID 1的reply_to_message_id = null。消息ID 2具有reply_to_message_id = 1。消息ID 3具有reply_to_message_id = 2,等等。该线程由每个指向其父项的子消息定义。线程中的第一条消息没有父项。每个答复都会。某人收件箱中的内容是指向发件人的邮件(MESSAGE.sender_user_id)或已发送的内容(通过RECIPIENT加入)。 sender_keep/recipient_keep是“标记为已读”功能。消息之间的关系用于将它们直观地排序为线程。 –