2015-12-21 18 views
2

這是我蒙戈集「銷售」:如何在MongoDB的每個組中分組和選擇對應於max的文檔?

{"title":"Foo", "hash": 17, "num_sold": 49, 
"place": "ABC"} 

{"title":"Bar", "hash": 18, "num_sold": 55, 
"place": "CDF"} 

{"title":"Baz", "hash": 17, "num_sold": 55, 
"place": "JKN"} 

{"title":"Spam", "hash": 17, "num_sold": 20, 
"place": "ZSD"} 

{"title":"Eggs", "hash": 18, "num_sold": 20, 
"place": "ZDF"} 

我想通過哈希組,以最大的「num_sold」返回文檔。因此,作爲輸出我希望看到:

{"title":"Baz", "hash": 17, "num_sold": 55, 
    "place": "JKN"} 

{"title":"Bar", "hash": 18, "num_sold": 55, 
    "place": "CDF"} 

我知道基本的聚合運算符的,這裏是我會怎麼組和獲得最大num_sold的,但我需要對應最大整個文檔,而不僅僅是值。

db.getCollection('sales').aggregate([ 
{$group: {_id: "$hash", max_sold : {$max: '$value'}}} 
]) 

在SQL中,我會加入它,但在mongo。我還讀到,在蒙戈組中排序並不能很好地協同工作。

+0

mongodb'您正在使用什麼版本的'? – BatScream

+0

@BatScream 3.0.4。我仍然在研究我的問題,看起來可以在客戶端的一個組中進行排序,但我不明白服務器和客戶端之間的區別。也似乎我可以用mapreduce完成相同的操作,但還不清楚如何。 – user1700890

+0

可以避免使用昂貴的'$ sort'和'$ group'方法。請參閱下面的答案,以便在服務器端完成。 – BatScream

回答

2

您可以使用$redact階段來完成此操作。它避免使用$sort,然後再次執行$group$unwind

  • $group通過_id並獲得各組的最大max_num_sold,累積使用$push操作員組中的所有文件。
  • $redact成每組子文件,僅保留那些具有最大max_num_sold在其num_sold

示例代碼:

db.getCollection('sales').aggregate([ 
{$group:{"_id":"$hash", 
     "max_num_sold":{$max:"$num_sold"}, 
     "records":{$push:"$$ROOT"}}}, 
{$redact:{$cond:[{$eq:[{$ifNull:["$num_sold","$$ROOT.max_num_sold"]}, 
         "$$ROOT.max_num_sold"]}, 
       "$$DESCEND","$$PRUNE"]}}, 
]) 

測試數據:

db.getCollection('sales').insert([ 
{"title":"Foo","hash":17,"num_sold":49,"place":"ABC"}, 
{"title":"Bar","hash":18,"num_sold":55,"place":"CDF"}, 
{"title":"Baz","hash":17,"num_sold":55,"place":"JKN"}, 
{"title":"Spam","hash":17,"num_sold":20,"place":"ZSD"}, 
{"title":"Eggs","hash":18,"num_sold":20,"place":"ZDF"} 
]) 

測試結果:

{ 
     "_id" : 18, 
     "max_num_sold" : 55, 
     "records" : [ 
       { 
         "_id" : ObjectId("567874f2b506fc2193a22696"), 
         "title" : "Bar", 
         "hash" : 18, 
         "num_sold" : 55, 
         "place" : "CDF" 
       } 
     ] 
} 
{ 
     "_id" : 17, 
     "max_num_sold" : 55, 
     "records" : [ 
       { 
         "_id" : ObjectId("567874f2b506fc2193a22697"), 
         "title" : "Baz", 
         "hash" : 17, 
         "num_sold" : 55, 
         "place" : "JKN" 
       } 
     ] 
} 
+0

非常感謝您提供這樣詳細的答案!我花了一段時間才明白。這是非常有創意的使用聚合框架。你知道在服務端或客戶端做些什麼意味着什麼嗎?我想充分研究這個問題,並嘗試使用map reduce。 – user1700890

+1

是的,但你做一個昂貴的操作是$ sort。但是,總是有辦法做到這一點。我給了你一個不同的方法來做到這一點:) – BatScream

+0

對不起,我發佈了替代解決方案與昂貴的排序和組分開爲更好的可讀性。 – user1700890

0

它看起來像MongoDB中的分組不變形秩序,這樣的事情是可能的:

mongodb, how to aggregate with group by and sort correctly

尤其是,上面的例子中,我們可以得到以下幾點:

db.getCollection('sales').aggregate([ 
{$sort: {"num_sold":-1}}, 
{$group:{"_id": "$hash", 
     "max_num_sold" : {$first:"$num_sold"}, 
     "title":{$first: "$title"}, 
     "place":{$first:"$place"} 
     }} 
]) 

這裏是輸出:

{ 
    "result" : [ 
     { 
      "_id" : 17.0000000000000000, 
      "max_num_sold" : 55.0000000000000000, 
      "title" : "Baz", 
      "place" : "JKN" 
     }, 
     { 
      "_id" : 18.0000000000000000, 
      "max_num_sold" : 55.0000000000000000, 
      "title" : "Bar", 
      "place" : "CDF" 
     } 
    ], 
    "ok" : 1.0000000000000000 
} 
相關問題