2011-06-21 46 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是「標記爲已讀」功能。消息之間的關係用於將它們直觀地排序爲線程。 –