2010-11-15 74 views
11

假設您有大量用戶(M)和大量文檔(N),並且您希望每個用戶都能夠將每個文檔標記爲讀或未讀(就像任何電子郵件系統一樣)。在MongoDB中表示這個最好的方法是什麼?或者其他任何文檔數據庫?MongoDB/NOSQL:處理郵件讀取/未讀狀態的最佳方法

有StackOverflow上幾個問題問這個問題,關係數據庫,但我沒有看到任何與建議文檔數據庫:

What's the most efficient way to remember read/unread status across multiple items?

Implementing an efficient system of "unread comments" counters

通常的答案涉及表上市用戶讀過的所有東西:(即用戶標識元組,文檔標識符),以及一些可能的最佳截止日期,允許標記全讀爲擦除數據庫並重新開始,因爲知道該日期之前的任何內容都是「讀取」。

那麼,MongoDB/NOSQL專家,你在實踐中看到了什麼方法來解決這個問題,他們是如何執行的?

回答

4
{ 
_id: messagePrefs_uniqueId, 
type: 'prefs', 
timestamp: unix_timestamp 
ownerId: receipientId, 
messageId: messageId, 
read: true/false, 
} 

{ 
_id: message_uniqueId, 
timestamp: unix_timestamp 
type: 'message', 
contents: 'this is the message', 
senderId: senderId, 
recipients: [receipientId1,receipientId2] 
} 

假設你有3個消息要檢索的喜好,你可以通過像讓他們:

db.messages.find({ 
messageId : { $in : [messageId1,messageId2,messageId3]}, 
ownerId: receipientId, 
type:'prefs' 
}) 

如果你需要的是讀/未讀您可以用MongoDB的UPSERT功能使用,因此除非用戶實際讀取消息,否則不會爲每條消息創建首選項,然後基本上使用自己的唯一標識創建首選項對象並將其插入MongoDB。如果你想要更多的靈活性(比如說標籤或者文件夾),你可能需要爲郵件的每個收件人制作pref。例如,你可以添加:

tags: ['inbox','tech stuff'] 

的首選項對象,然後拿到標有「高科技的東西」,你會去有點像所有消息的所有首選項:

db.messages.find({type: 'prefs', ownerId: recipientId, tags: 'tech stuff'}) 

你可以然後用你的首選項中找到messageIds查詢,發現所有的對應消息:

db.messages.find((type:'message', _id: { $in : [array of messageIds from prefs]}}) 

如果你想要做這樣的事情多少消息計數這可能是一個有點棘手每個'標籤'包含有效。如果只有少數標籤,則可以將.count()添加到每個查詢的查詢末尾。如果數以百計或數以千計,那麼使用map/reduce服務器端腳本或者可能跟蹤每個用戶每個標記的郵件計數的對象可能會更好。

+1

謝謝,所以你的推薦基本上和關係案例中的'tuple/join'表是一樣的,對吧?您將這兩個消息和首選項存儲在同一個集合中的任何特定原因? – 2010-11-15 03:11:16

+0

MongoDB的東西通常是讓你的對象更好的平坦。雖然它可以存儲嵌套結構,但在查詢或稍後進入這些結構以改變它們時,它並不是最好的。所以很多東西最終可能會看起來類似於關係,但是由於不使用表格而抽象程度較低。另外,我真的沒有理由將它們存儲在同一個集合中,而不喜歡擁有bazillion集合。如果你計劃擁有數百萬條消息,那麼使用不同的集合可能是明智的,這樣你就可以設置索引來更好地適應每個對象。 – Klinky 2010-11-15 04:46:57

3

如果你只存儲一個簡單的布爾值,如read/unread,另一種方法是在每個Document中嵌入一個數組,其中包含讀取它的用戶列表。

{ 
    _id: 'document#42', 
    ... 
    read_by: ['user#83', 'user#2702'] 
} 

然後,您應該能夠索引字段,從而實現快速查詢的文檔讀取通過用戶和用戶 - 誰 - 讀文件。

db.documents.find({read_by: 'user#83'}) 

db.documents.find({_id: 'document#42}, {read_by: 1}) 

然而,我發現,我通常查詢有由特定用戶讀取所有的文檔,我想不出任何解決方案,可以利用指數在此的案件。我猜想如果沒有read_byunread_by數組,這樣就無法做到這一點,所以每個用戶都包含在每個文檔(或連接表)中,但這會產生很大的存儲成本。

+0

關於查詢*未讀*消息但使用* read_by *字段的最後一點,請糾正我,如果我錯了,但不能** $ not **子句實現這一點,如'$ not:{$在:[{id:'user#83'}]}'? – bigp 2017-10-24 13:53:31

相關問題