Salta el contingut

4. Consultese en Mongo

4.1. find()

La comanda find ens permet recuperar els documents d'una col·lecció que coincideixen amb un criteri especificat com a document JSON. La seva sintaxi bàsica és la següent:

JavaScript
db.collection.find({criteria_in_JSON_format});
Hem de tenir en compte aspectes com els tipus de dades que utilitzem, que és important, ja que el document {edad:20} no és el mateix que {edad:"20"}.

D'altra banda, també hem de considerar que el document buit {} coincideix amb tots els documents, de manera que la consulta db.collection.find({}) retornaria tots els objectes de la col·lecció.

4.1.1. Quines claus recuperar?

La comanda find retorna els documents complets que coincideixen amb els criteris de selecció. Si no volem obtenir totes les claus, podem especificar quines claus volem consultar, incloent-les en un segon paràmetre:

JavaScript
db.collection.find({query_document}, {key_1:1, key_2:1});

Com podem veure, aquest segon paràmetre també s'expressa en format JSON (de nou) i està format per dues claus (key_1 i key_2), ambdues amb un valor d'1. Aquest valor numèric també s'interpreta com a true. És a dir, especifiquem aquí quins són els camps que volem mostrar. En cas que vulguem mostrar tots els camps i amagar-ne alguns, utilitzaríem la mateixa sintaxi, però ara fent servir un 0 per aquells camps que volem amagar.

4.1.2. Operacions de comparació

MongoDB ens permet realitzar comparacions amb dades numèriques, sempre utilitzant el format de document JSON db.collection.find({key: {$operator:value} });

Els operadors de comparació que podem utilitzar a MongoDB són:

  • $lt → Menor que
  • $lte → Menor o igual que
  • $gt → Major que
  • $gte → Major o igual que

4.1.3. Operació OR

Si volem realitzar un filtre o consulta on es compleixin diverses condicions (una operació AND), només haurem de separar-les per comes en el mateix document JSON que utilitzem com a criteri. D'altra banda, si el que volem és dur a terme una operació OR, hem d'utilitzar un operador especial.

4.1.4. Operadors $IN i $NIN

Un cas especial d'OR és quan volem comprovar si un camp es troba dins d'un conjunt específic de valors. És a dir, si és un valor o un altre. Per això utilitzem l'operador $in, de la següent manera:

JavaScript
db.collection.find({key:{$in:[vector_de_valors]}})

De manera similar, existeix l'operador $nin (Not In), que obté els documents on el valor especificat no es troba a la llista. Hem de tenir en compte que en aquest últim cas també es mostraran aquells documents que tinguin un valor nul per a la clau.

4.1.5. Operador $OR

Quan volem realitzar l'operació OR en diferents camps del document, utilitzarem l'operador $OR, al qual passem un vector de possibles condicions, de la següent manera:

JavaScript
db.collection.find({$or:[condition1, condition2,...]})

Attention

Les condicions del array son condicions en json

4.1.6. Operador $NOT

L'operador $NOT és un operador metacondicional, és a dir, sempre s'aplica a un altre criteri, invertint el seu valor de certesa. La seva sintaxi seria:

JavaScript
db.collection.find({key:{$not: {criterion}}}).pretty();

4.1.7. Operador $EXISTS

Recordem que en MongoDB, els documents no tenen una estructura o esquema comú, per la qual cosa és possible que hi hagi claus definides només en alguns d'ells. L'operador $exists s'utilitza per comprovar l'existència o no d'una determinada clau. La sintaxi a utilitzar seria:

JavaScript
db.collection.find({key:{ $exists: true|false }})

Amb això obtenim els documents per als quals la clau existeix o no, depenent de si hem indicat true o false a la consulta.

4.2. Resultats de les consultes i tipus de dades

Els tipus de dades a MongoDB poden tenir alguns comportaments especials. Veurem alguns casos per saber què fer en determinades situacions.

4.2.1. valors nulls

El valor null coincideix amb les següents situacions:

  • Quan el valor de la clau és null, o
  • Quan la clau no existeix en el document (en aquest cas, normalment es diu que el camp no està informat)

4.2.2. Expressions regulars i cadenes de caràcters

Quan apliquem un filtre de document per un camp de text, pot ser que no coneguem exactament el valor del camp pel qual volem filtrar. Les expressions regulars ofereixen un mecanisme molt potent per a la coincidència de cadenes.

MongoDB ens permet utilitzar aquestes expressions de diverses maneres, ja sigui utilitzant expressions regulars de Javascript o utilitzant l'operador $regex, que utilitza Expressions Regulars Compatibles amb Perl (PCRE). Les expressions regulars de Javascript s'expressen utilitzant la següent sintaxi:

JavaScript
{ key: /pattern/<options> }

Com podem veure, utilitzem un patró similar a una cadena de text, però utilitzant la barra inclinada / com a delimitador en lloc de les cometes ('). Per la seva banda, si utilitzem l'operador $regex, podem utilitzar la següent sintaxi:

JavaScript
1
2
3
{ key: { $regex: /pattern/, $options: '<options>' } }
{ key: { $regex: 'pattern', $options: '<options>' } }
{ key: { $regex: /pattern/<options> } }

Podem trobar diverses opcions per a expressions regulars:

  • i → Les coincidències no distingeixen entre majúscules i minúscules:
    • {name:/john/i}
    • {name: { $regex: 'john',$options: 'i'}}
  • m → Permet incloure caràcters com ^ o $, per coincidir al principi o al final, en cadenes amb múltiples línies.
    • {name:/^John/m}
    • {name: { $regex: 'John', $options: 'm'}}
  • x Ignora els espais en blanc en el patró $regex, sempre que no estiguin escapats o inclosos en una classe de caràcters.
    • {name: { $regex: ' J oh n',$options: 'x'}}
  • s Permet que el caràcter punt (.) representi qualsevol caràcter, incloent el caràcter de nova línia.
    • {name:/ju.n/s}
    • {name: { $regex: 'thu.n',$options: 's'}}

Podeu trobar més informació sobre expressions regulars i casos particulars en què es recomana utilitzar un tipus d'expressió o una altra en la documentació oficial de MongoDB sobre $regex aquí.

4.3. Consideracions sobre el tipus de dades de les consultes

4.3.1. Consultes amb arrays

Per cercar elements coincidents dins d'un array, procedim amb la mateixa sintaxi com si fos qualsevol altra clau, utilitzant el document de consulta {key:value}, sent la clau un array, i el valor, ja sigui un n valor que ha de contenir l'array, o un altre vector ordenat que volem que coincideixi exactament.

Per exemple:

  • db.collection.find({ my_vector : value }) → Coincideix amb tots els documents en els quals el vector my_vector apareix, en la posició que sigui, el valor indicat.
    • db.users.find({roles:"admin"}) mostra els usuaris que en l'array roles tenen el rol admin (o altres).
  • db.collection.find({ my_vector : [value] }) → Coincideix amb tots els documents en els quals el vector my_vector apareix només el valor indicat.
    • db.users.find({roles:["admin"]}) mostra els usuaris que tenen exactament el rol admin.

A més, també podem utilitzar expressions regulars o la resta d'operadors que hem vist com a condicions.

D'altra banda, també podem referir-nos a un element específic del vector pel seu índex, utilitzant la notació de punts i entre cometes:

  • db.collection.find({"my_vector.position" :[value]})
    • db.users.find({"roles.2":["admin"]}) mostra l'usuari que té com a tercer rol admin

4.3.2. L'operador $all

Amb $all podem especificar més d'un element coincident dins de l'array:

  • db.collection.find({ my_vector : {$all:[value1, value2,...]}})
    • db.users.find({roles:{$all:["mod","admin"]}}) mostra els usuaris que tenen els rols mod i admin (i possiblement altres).

4.3.3. L'operador $size

Utilitzant $size podem incloure condicions sobre la longitud dels vectors:

  • db.collection.find({ my_vector : {$size:size} })

4.3.4. L'operador $slice

L'operador slice ens permet obtenir un subconjunt dels elements del vector, amb la següent sintaxi:

  • key: {$slice: x}:
    • si x>0 obté els primers x elements
    • si x<0, obté els últims x elements
  • key: {$slice: [ x , y ] } Obtén y elements des de l'element a la posició x del document embegut

Per consultar documents embeguts, simplement especifiqueu el camí complet de la clau, tancat entre cometes i separat per punts: db.collection.find({"path.to.key":value_or_condition})

4.4. Cursors

Quan realitzem una consulta, MongoDB retorna els resultats utilitzant cursos, que són punters als resultats de la consulta, com connectors a la unitat 2. Els clients que utilitzen Mongo iteren sobre aquests cursos per recuperar els resultats, i ofereixen un conjunt de funcionalitats, com limitar els resultats, etc.

Quan realitzem una consulta en una base de dades amb molts resultats, el client (mongosh) retorna només 20 resultats i el missatge Type "it" for more, per continuar iterant el cursor.

4.4.1. Limit, Skip i Sort

MongoDB ens permet fer certes limitacions en els resultats. Entre elles, podem destacar:

  • limit → Per limitar el nombre de resultats
  • skip → Salta un nombre específic de resultats.
  • sort → Ordena els resultats. Necessites un objecte JSON amb les claus per ordenar, i un valor de 1 per ordenar ascendentment o -1 per ordenar descendentment.

4.5. Introducció al Marc d'Agrupació

Les consultes d'agrupació que realitzàvem amb operadors com GROUP BY, SUM o COUNT en SQL es poden realitzar amb el Marc d'Agrupació de MongoDB. Les consultes d'agrupació tenen la següent sintaxi:

JavaScript
db.collection.aggregate( [<pipeline>] )

El pipeline o tuberia té un concepte similar a les tiberies d'Unix: els resultats d'una ordre es passen com a entrada a una altra, per obtenir resultats conjuntament.

Les operacions que podem realitzar dins d'aquestes consultes d'agrupació són:

  • $project → Per realitzar una projecció sobre un conjunt de dades d'entrada, afegint, eliminant o recalculant camps perquè la sortida sigui diferent.
  • $match → Filtra l'entrada per reduir el nombre de documents, deixant només aquells que compleixen certes condicions.
  • $limit → Restringeix el nombre de resultats.
  • $skip → Salta un cert nombre de registres.
  • $unwind → Converteix un array per retornar-lo separat en documents.
  • $group → Agrupa documents segons una certa condició.
  • $sort → Ordena un conjunt de documents, segons el camp especificat.
  • $geoNear→ S'utilitza com a dades geoespacials, retornant els documents ordenats per proximitat segons un punt geoespacial.

Per realitzar càlculs sobre les dades produïdes per les canonades, utilitzarem expressions. Les expressions són funcions que realitzen una certa operació sobre un grup de documents, vector o camp específic. Algunes d'aquestes expressions són $max, $min, $divide o $substr.

Podeu trobar molta més informació sobre agregacions a la documentació oficial de MongoDB.

4.6. Exercicis

Seguim treballant amb la col·lecció de pel·lícules. En aquest cas, utilitzarem el terminal mongosh (o robo3t si ho prefereixes), i realitzarem les següents consultes sobre aquesta col·lecció.

  1. Obteniu totes les produccions que es van estrenar el 2015 o que són del tipus sèrie.
  2. Obteniu totes les pel·lícules que NO es van estrenar entre els anys 2000 i 2002.
  3. Obteniu totes les pel·lícules per a les quals la clau "directors" no està definida.
  4. Obteniu el títol de totes les pel·lícules que comencen amb la cadena star wars, independentment de majúscules o minúscules.
  5. Obteniu el títol de totes les pel·lícules que contenen el gènere comèdia (Comedy).
  6. Mostreu el títol i els gèneres de les pel·lícules que contenen el gènere comèdia (Comedy) o aventura (Adventure).
  7. Obteniu el títol i els gèneres de les pel·lícules que tenen tres gèneres.
  8. Obteniu les pel·lícules amb una qualificació de Rotten Tomatoes superior a 4.
  9. Feu la mateixa consulta que abans, però limitant el nombre de documents a 10.
  10. Ara mostreu el títol i la qualificació d'aquelles pel·lícules amb una qualificació superior a 4, ordenades per qualificació (de més alta a més baixa) i limitant els resultats a 10.