DAM - DAW - MP 0484 Bases de Dades
Aggregation pipeline
Per a fer operacions amb grups de documents, l’equivalent al group by del sql, mongoDB ens dóna tres opcions diferents: la tuberia d’agregació (aggregation pipeline), la funció MapReduce, i operacions d’agregació amb propòsit simple. Anem a veure la primera opció: Aggregation pipeline.
Per utilitzar la tuberia d’agregació de MongoDB, utilitzarem el mètode aggregate de la col·lecció sobre que vulguem realitzar operacions. Aquesta comanda rep com a paràmetre un array d’etapes, en les que cada etapa és un objecte que representa una operació a realitzar. Funciona com una tuberia (pipe), ja que les dades passen per les etapes en l’ordre en què les trobem dins l’array.
La sintaxis per executar una comanda d’agregació és:
db.collection.aggregate( [ { stage1 } , { stage2 } , { stage3 } , { ... } ], options)
Cada etapa està formada per un operador d’etapa que representa la funció i un objecte que representen una o vàries expressions que passem com a paràmetre a la funció.
Els operadors s’anomenen operadors d’etapa:
$match
{ $match: { <query> } }
Aquest operador funciona de forma semblant al mètode find(). Ho veurem en un exemple:
db.estudiants.aggregate( [ { $match : {nom : 'Pilar'} } ] )
D’aquesta manera estarem filtrant les files dels registres que volem seleccionar.
$project
{ $project: { <specification(s)> } }
Permet modificar una dada i expressar-la de la forma en què ens sembli millor segons les especificacions que passem com a paràmetre, ja sigui eliminant camps o afegint-ne amb l’ús d’altres expressions.
db.estudiants.aggregate( [ { $project : {nom : 1, _id : 0} } ] )
També podem canviar el nom d’un camp o bé crear-ne un de nou a partir d’una expressió:
db.estudiants.aggregate( [ { $project : {nom:1, altreNom:"$nom" } } ] )
MongoBD també ens permet utilitzar operadors i crear camps nous a partir d’altres aplicant-los algunes funcions com ara $concat.
db.estudiants.aggregate([{$project : {_id:0, nomComplet : {$concat : ["$nom"," ","$cognom"]}}}])
$sort
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
Permet ordenar els documents que hem obtingut. Com a paràmetre cal posar-hi els camps que cal utilitzar per a ordenar i un ordre (1 indica ordre ascendent i -1 indica ordre descendent).
db.estudiants.aggregate([{$project : {nom:1,edat:1,_id:0}},{$sort : {edat : 1}}])
$limit
{ $limit: <positive 64-bit integer> }
Permet limitar el nombre de documents obtinguts amb un valor enter que passem com a paràmetre.
db.estudiants.aggregate([{$project:{nom:1,edat:1,_id:0}},{$sort:{edat:1}},{$limit:3}])
$skip
{ $skip: <positive 64-bit integer> }
Permet saltar-nos els n primers documents obtinguts amb un valor enter que passem com a paràmetre.
db.estudiants.aggregate([{$project:{nom:1,edat:1,_id:0}},{$sort:{edat:1}},{$skip:2}{$limit:3}])
Recorda que les etapes d’una agregació s’executen en el mateix ordre en què les hem posat dins l’array
Per tant, si posem $limit abans de $skip, llavors $skip rebrà els documents ja limitats a cert nombre i potser no obtindrem les dades desitjades. Normalment $limit el posem al final, després d’haver filtrat i ordenat
$count
{ $count: <string> }
Permet obtenir el nombre de documents que hi ha a l’etapa específica. Passem com a a paràmetre una cadena de caràcters/string que servirà com alias a la consulta.
db.estudiants.aggregate([{$match : {edat : { $lt : 18}}}, {$count : "Estudiants menors de 18 anys"}])
$group
{ $group: { _id: , : { : }, … } }
La comanda group agrupa documents segons una determinada expressió i genera un nou document per a cada grup que serà la sortida generada per aquesta etapa i l’entrada per la següent.
Cada document generat està format per un _id que tindrà com valor el resultat de l’expressió que serà la clau primària del document, per tant, aquest _id és obligatori.
Opcionalment, pot contenir camps adicionals obtinguts a través d’operador d’acumulació o acumuladors que ja veurem. Tant l’_id com els acumuladors accepten com a paràmetre una expressió vàlida.
db.estudiants.aggregate([{$group:{_id:{$lt:['$edad',18]},edats:{$push:{edat:'$edat'}}}}])
db.estudiants.aggregate([{$group : { _id : '$cicle', quants : {$sum : 1}}}])
$sample
{ $sample: { size: <positive integer N> } }
``
Permet obtenir una mostra aleatòria de *n* documents on *n* és un enter positiu que passem com valor del paràmetre `size`.
```js
db.estudiants.aggregate([{$sample : {size : 2}}])
$out
{ $out: { db: "<output-db>", coll: "<output-collection>" } }
Aquest operador permet obtenir els documents de la tuberia d’agregació i afegir-los en una col·lecció específica. Només s’ha d’utilitzar com a darrera etapa de la tuberia.
db.estudiants.aggregate([{$group : { _id : '$programa', count : {$sum : 1}}},{$out : 'programes'}])
No podem veure’n la sortida ja que aquesta va directament a la nova col·lecció.
Aquesta nova col·lecció es crea de nou i si ja tingués documents dins aquests serien eliminats abans d’afegir-hi els nostres.
$addFields
{ $addFields: { <newField>: <expression>, ... } }
Aquest operador permet afegir camps a una col·lecció de documents, especificant el nom dels nous camps a afegir, cadascun amb una expressió que generarà el valor del nou campo per cada document.
db.estudiants.aggregate([{$addFields : { totalNotes : { $sum : '$notes' }, esMembreDeClub : { $gt : ['$grups',null]}}}])
Aquí, al no poder utilitzar $exists en agregats (només està disponible en querys), al comparar un array amb null ($gt) si l’array té valors es considera major que null i per tant retornarà cert.
$sortByCount
{ $sortByCount: <expression> }
Aquest operador permet fer un $group donada una expressió passada com a paràmetre i un $count de tots els elements, i posteriorment, ordenar-lo segons el nombre d’elements de forma descendent.
db.estudiants.aggregate([{$sortByCount : '$semestre'}])
$unwind
{ $unwind: <field path> }
Desconstrueix un camp de matriu dels documents d'entrada per treure com a sortida un document per a cada element de l'array. Cada document de sortida és el document d'entrada amb el valor del camp de matriu substituït per l'element. D'aquesta manera acabem tenint, per cada document inicial, tants documents com elements té l'array.
db.alumnes.aggregate([{$unwind : '$Moduls'}])
Hi ha molts més stage per treballar dins la pipeline però aquests són els que he cregut més interessants