2012-10-24 7 views
7

È possibile utilizzare il framework di aggregazione per raggruppare un elemento specifico di un array?Raggruppa per elemento specifico dell'array con il framework di aggregazione di mongo

tale che, con documenti come questo:

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

ho potuto ottenere una lista distinta di cibi preferiti top (cioè alimenti a indice 0.) Insieme con l'altezza della persona più alta che è cibo di alta preferito che è ?

Qualcosa di simile (anche se non funziona come l'indice di matrice accesso notazione non sembra funzionare nel quadro di aggregazione):

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

risposta

5

sembra che al momento non è possibile estrarre un elemento specifico da un array di aggregazione: https://jira.mongodb.org/browse/SERVER-4589

+0

Sì, l'ho notato. Ho sperato che qualcuno avesse inventato una soluzione ... – Russell

+0

non puoi estrarre un elemento arbitrario per posizione, ti capita di avere un modo per ottenere il primo o l'ultimo tramite $ unwind e re $ group con $ first o $ last operator. –

+1

** Buone notizie **: il problema è stato risolto con [l'operatore $ arrayElementAt] (https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/) – joeytwiddle

2

penso che si può fare uso del progetto $ e $ rilassarsi operatori (fatemi sapere se questo non è ciò che si sta cercando di realizzare):

> 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

che includerà tutti gli alimenti preferiti elenco, non solo top uno ... Burger non è la migliore scelta di nessuno in questo set di dati estremamente piccolo :) –

+0

@asya è giusto, voglio solo il primo cibo dall'array – Russell

+0

doh. colpa mia. bello, Asya. – Jenna

14

Sembra come si fa affidamento sul cibo preferito per ogni persona di essere primo nella matrice. Se è così, c'è un operatore di framework di aggregazione da cui puoi trarre vantaggio.

Ecco la pipeline è possibile utilizzare:

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

Su questo set di dati campione:

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

ottenere questi risultati:

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

se il nome non è univoco, puoi usare _id al suo posto nel primo gruppo $. –

+0

Bella soluzione, ma si basa sui documenti prodotti dallo svolgimento mantenendo il loro ordine ordinato - puoi contare su questo ed è documentato da qualche parte come tale? – Russell

+0

So che è come funziona da più prove, e mentre non è nei documenti, ho guardato il codice sorgente e sembra essere il caso. vedere: https://github.com/mongodb/mongo/blob/master/src/mongo/db/pipeline/document_source_unwind.cpp –

0

Basta aggiungere ulteriori informazioni sulla risultato dopo l'utilizzo di "$wind":


DOCUMENTO:

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


RISULTATO:

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


Inoltre:
Se ci sono più di due campi di array in un record di raccolta, possiamo usare "$project" palco per specificare il campo array.

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