2013-09-30 20 views
2

我收集了以下字段的消息:_id,senderId,receiverId,dateSubmittedMs,message,對於給定的用戶,我想從其他所有用戶返回最新的消息給他。因此,例如,如果有Alex,Barb,Chuck,Dora等用戶,我想返回Alex與Barb,Chuck和Dora各自之間的最新消息。做這個的最好方式是什麼?我可以使用聚合一步完成嗎?

官方在線文檔(http://docs.mongodb.org/manual/reference/aggregation/min/)中的聚合示例顯示瞭如何查找集合內組的最低年齡,但我需要的是類似於找到最不老的人的姓名。

這是我目前的做法:

第1步:查找dateSubmitted在發送和亞歷克斯收到的所有消息中的最高值,比其他用戶分組:

var M = Messages.aggregate(
{$match: 
    {$or: [{senderId: 'Alex'}, {receiverId: 'Alex'}]} 
}, 
{$group: {_id: "$receiverId", lastestSubmitted: {$max: "$submitted"} }}).fetch(); 

第2步:創建

var MIds = _.pluck(M,'lastestSubmitted'); 

步驟3::dateSubmitted的這些最高值的陣列查找這些消息,通過senderId,receiverId和latestSubmitted:

return Messages.find(
    {submitted: {$in: MIds}, $or: [{senderId: 'Alex'}, {receiverId: 'Alex'}]}, 
    {$sort: {submitted: 1}} 
}); 

有兩個問題:

  1. 可以在一個步驟中而不是三個做些什麼呢?也許通過mapReduce或Aggregate命令?
  2. 而不是隻分組在receiverId: 'Alex',有沒有一種方法來組合,如:$or [{receiverId: 'Alex', senderId: 'Barb'}, {senderId: 'Alex', receiverId: 'Barb'}]? (但是對於其他用戶)這將使我能夠在Alex交談的任何兩個參與者之間的對話中獲得最新消息。例如:

有什麼建議嗎?

回答

1

您唯一需要更改的是grougping階段的group._id。雖然您可以爲此使用文檔,但不只是一個字段,您可以在相同的管道中應用這種排序。但是,如果僅使用receiverId進行分組,則不會發生變化。

var M = Messages.aggregate(
{$match: 
    {$or: [{senderId: 'Alex'}, {receiverId: 'Alex'}]} 
}, 
{$group: 
    {_id: { 
      receiverId: "$receiverId", 
      senderId: "$senderId"}, 
     lastestSubmitted: {$max: "$submitted"} } 
}, 
{$sort: {submitted: -1} 
}, 
{$limit: 1} 
).fetch(); 

這上面的例子只是增加的方法可行,檢查第二最近ping通連接或第三個,如果你只可能得到最新的消息,你甚至都不需要組。只要運行這個:

var M = Messages.aggregate(
{$match: 
    {$or: [{senderId: 'Alex'}, {receiverId: 'Alex'}]} 
}, 
{$sort: {submitted: -1} 
}, 
{$limit: 1} 
).fetch(); 

高於這個答案是用於獲取最新的信息之間的單一使用者或其他人,要獲得所有對涉及請閱讀>>>

用戶之間最近的信息根據評論我誤解了一些問題,但上面的部分是有用的。你的問題正確的解決方案是在。在這種情況下,難點在於獲得一對鑰匙來分組並識別轉換對(bob - > tom == tom - > bob)。 U可以使用條件和順序來確定交換。(這當然是一個更加棘手的問題)的代碼是這樣的:

var M = Messages.aggregate(
{$match: 
    {$or: [{senderId: 'Alex'}, {receiverId: 'Alex'}]} 
}, 
{$project: 
    {'part1':{$cond:[{$gt:['$senderId','$receiverId']},'$senderId','$receiverId']}, 
    'part2':{$cond:[{$gt:['$senderId','$receiverId']},'$receiverId','$senderId']}, 
    'message':1, 
    'submitted':1 
    } 
}, 
{$sort: {submitted: -1}}, 
{$group: 
    {_id: { 
      part1: "$part1", 
      part2: "$part2"}, 
     lastestSubmitted: {$first: "$submitted"}, 
     message: {$first: "$message"} } 
} 
).fetch(); 

如果你不熟悉一些上面使用的運營商,比如$ COND或$,先看看this

+0

謝謝你。我試着實現它,如果Meteor支持聚合客戶端,它可能會工作,但正如我剛纔發現的(http://stackoverflow.com/questions/11266977/are-group-by-aggregation-queries-possible-流星尚未),流星還沒有。有一個解決方法(https://github.com/meteor/meteor/pull/644),但它沒有反應。我會在mongodb shell中試試這個,看看我能否在那裏工作,只是爲了確保。 –

+0

我在shell中試過並複製粘貼我開發的代碼給你的例子。老實說,我沒有嘗試在流星,而我認爲你的問題的代碼工作。我對你的測試很好奇,如果你能提供結果,那將會很棒。無論如何,我希望這有助於。 – attish

+0

您好@attish,感謝您的關注。我嘗試在mongodb shell中實現兩個解決方案,但它們總體返回1個結果,而他們應該返回每個對話的一個結果(如果Alex與Barb和Chuck進行了對話,則應返回兩個結果:最新消息與倒鉤和最新的消息與查克)。你是否能夠獲得不止一個結果? –

相關問題