2012-10-24 68 views
7

是否可以使用聚合框架按數組的特定元素進行分組?按mongo聚合框架排列的數組特定元素

使得具有這樣的文件:

{ 
    name: 'Russell', 
    favourite_foods: [ 
    { name: 'Pizza', type: 'Four Cheeses' }, 
    { name: 'Burger', type: 'Veggie'} 
    ], 
    height: 6 
} 

我能得到的最高愛吃的食物獨特的名單(即索引0食物。)與最高的人的身高是誰的頂部最喜歡的食物是沿?

像這樣的東西(雖然它不作爲數組索引訪問點符號的工作似乎並沒有在聚合框架工作):

db.people.aggregate([ 
    { $group : { _id: "$favourite_foods.0.name", max_height: { $max : "$height" } } } 
]) 

回答

5

看起來它是目前無法提取從陣列中聚集特定的元素: https://jira.mongodb.org/browse/SERVER-4589

+0

是的,我發現了。我有點希望有人提出了一個解決方法... – Russell

+0

你不能提取位置的任意元素,你碰巧有辦法通過$ unwind獲取第一個或最後一個元素,並用$ first或$ last操作符重新獲得$ group。 –

+1

**好消息**:該問題最終通過[arrayElementAt運算符](https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/) – joeytwiddle

2

我想你可以使用$項目和$放鬆運營商(讓我知道如果這是你要完成不算什麼):

> db.people.aggregate(
    {$unwind: "$favourite_foods"}, 
    {$project: {food : "$favourite_foods", height: 1}}, 
    {$group : { _id: "$food", max_height: { $max : "$height" } } }) 


{ 
    "result" : [ 
     { 
      "_id" : { 
       "name" : "Burger", 
       "type" : "Veggie" 
      }, 
      "max_height" : 6 
     }, 
     { 
      "_id" : { 
       "name" : "Pizza", 
       "type" : "Four Cheeses" 
      }, 
      "max_height" : 6 
     } 
    ], 
    "ok" : 1 
} 

http://docs.mongodb.org/manual/applications/aggregation/

+0

解決,它將包括所有最喜歡的食物名單,不只是頂級的...漢堡不是任何人在這個非常小的數據集的首選:) –

+0

@asya是正確的,我只想要第一個食物從陣列 – Russell

+0

doh。我的錯。好的,Asya。 – Jenna

14

好像你是依靠每個人的首選陣列中最喜歡的食物。如果是這樣,那麼您可以利用一個聚合框架運算符。

這裏是管道可以使用:

db.people.aggregate(
[ 
    { 
     "$unwind" : "$favourite_foods" 
    }, 
    { 
     "$group" : { 
      "_id" : { 
       "name" : "$name", 
       "height" : "$height" 
      }, 
      "faveFood" : { 
       "$first" : "$favourite_foods" 
      } 
     } 
    }, 
    { 
     "$group" : { 
      "_id" : "$faveFood.name", 
      "height" : { 
       "$max" : "$_id.height" 
      } 
     } 
    } 
]) 

這個樣本數據集:

> db.people.find().pretty() 
{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" : [ 
     { 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Burger", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 6 
} 
{ 
    "_id" : ObjectId("5088950bd4197aa2b9490742"), 
    "name" : "Lucy", 
    "favourite_foods" : [ 
     { 
      "name" : "Pasta", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Burger", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 5.5 
} 
{ 
    "_id" : ObjectId("5088951dd4197aa2b9490743"), 
    "name" : "Landy", 
    "favourite_foods" : [ 
     { 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Pizza", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 5 
} 
{ 
    "_id" : ObjectId("50889541d4197aa2b9490744"), 
    "name" : "Augie", 
    "favourite_foods" : [ 
     { 
      "name" : "Sushi", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Pizza", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 6.2 
} 

你得到這些結果:

{ 
    "result" : [ 
     { 
      "_id" : "Pasta", 
      "height" : 5.5 
     }, 
     { 
      "_id" : "Pizza", 
      "height" : 6 
     }, 
     { 
      "_id" : "Sushi", 
      "height" : 6.2 
     } 
    ], 
    "ok" : 1 
} 
+0

如果名稱不唯一,則可以在第一個$組中使用_id。 –

+0

不錯的解決方案,但它依賴於展開的文檔保留它們的排序順序 - 你能依靠這個嗎?它是否被記錄在某處? – Russell

+0

我知道它是如何從多個試驗中工作的,儘管它不在文檔中,但我確實看過源代碼,它似乎就是這種情況。請參閱:https://github.com/mongodb/mongo/blob/master/src/mongo/db/pipeline/document_source_unwind.cpp –

0

只需添加有關的更多信息使用後的結果"$wind"


文獻:

> db.people.find().pretty() 
{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" : [ 
     { 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Burger", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 6 
}, 
... 


AGGREAGATION:

db.people.aggregate([{ 
    $unwind: "$favourite_foods" 
}]); 


結果:

{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" :{ 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
    }, 
    "height" : 6 
}, 
{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" : { 
      "name" : "Burger", 
      "type" : "Veggie" 
    }, 
    "height" : 6 
} 


另外:
如果有一個收集記錄, 兩個以上的陣列領域,我們可以使用"$project"階段指定數組字段。

db.people.aggregate([ 
    { 
     $project:{ 
      "favourite_foods": 1 
     } 
    }, 
    { 
     $unwind: "$favourite_foods" 
    } 
]);