2012-10-24 11 views
7

Czy możliwe jest wykorzystanie struktury agregacji do grupowania według określonego elementu tablicy?Grupowanie według określonego elementu tablicy ze strukturą agregacji mongo

taka, że ​​z dokumentów takich jak ten:

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

mogę uzyskać odrębną listę najlepszych ulubionych potraw (czyli żywność o indeksie 0.) Wraz z wysokością najwyższego osoby Top ulubioną potrawę, która jest ?

Coś takiego (chociaż to nie działa jak notacji dostęp dot indeksu tablicy nie wydają się działać w ramach agregacji):

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

Odpowiedz

5

Wygląda na to, że nie jest obecnie możliwe, aby wyodrębnić konkretny element tablicy w agregacji: https://jira.mongodb.org/browse/SERVER-4589

+0

Tak, zauważyłem to. Miałem nadzieję, że ktoś wymyślił obejście ... – Russell

+0

nie można wyodrębnić dowolnego elementu według pozycji, zdarza się, że masz sposób na uzyskanie pierwszego lub ostatniego wyniku przez $ unwind i re $ group z pierwszym lub ostatnim operatorem $. –

+1

** Dobra wiadomość **: Problem został ostatecznie rozwiązany za pomocą operatora $ arrayElementAt (https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/) – joeytwiddle

2

myślę, że można skorzystać z projektu $ i $ odpoczynek operatorzy (daj mi znać, jeśli nie jest to, co starasz się osiągnąć):

> 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

, który obejmie wszystkie produkty spożywcze w ulubionych lista, nie tylko pierwsza ... Burger nie jest niczyim wyborem w tym bardzo małym zbiorze danych :) –

+0

@asya ma rację, chcę tylko pierwszego jedzenia z tablicy – Russell

+0

doh. mój błąd. miło, Asiu. – Jenna

14

Wygląda na to, że opierając się na ulubionym pokarmem dla każdej osoby będącej pierwszą w tablicy. Jeśli tak, istnieje operator agregacji, z którego możesz skorzystać.

Oto rurociąg można użyć:

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

Na tej próbki zbiorze:

> 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 
} 

dostać te wyniki:

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

jeśli nazwa nie jest unikalna, możesz użyć _id w swoim miejscu w pierwszej grupie $. –

+0

Ładne rozwiązanie, ale opiera się na dokumentach powstałych podczas rozwijania, zachowując uporządkowany porządek - czy można na tym polegać i czy dokumentuje się go gdzieś jako taki? – Russell

+0

Wiem, że tak działa z wielu prób, i chociaż nie jest to w dokumentach, spojrzałem na kod źródłowy i wygląda na to, że tak jest. zobacz: https://github.com/mongodb/mongo/blob/master/src/mongo/db/pipeline/document_source_unwind.cpp –

0

po prostu dodaj więcej informacji o Wynik po użyciu "$wind":


dokument:

> 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" 
}]); 


WYNIK:

{ 
    "_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 
} 


dodatkowo:
Jeśli istnieje więcej niż dwa pola tablicy w jeden rekord zbiórki, możemy użyć "$project" etap określić pola tablicy.

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