1. Libros y videos
  2. MongoDB
  3. Realizar consultas en MongoDB
Extrait - MongoDB Comprensión y optimización de la gestión de datos (con ejercicios y soluciones)
Extractos del libro
MongoDB Comprensión y optimización de la gestión de datos (con ejercicios y soluciones) Volver a la página de compra del libro

Realizar consultas en MongoDB

Buscar información usando find y findOne

Los métodos find y findOne tienen exactamente la misma firma. Tomemos el método find:

db.collection.find( <consulta>, <proyección>) 

Los parámetros consulta y proyección son ambos documentos: el primero detalla la consulta, mientras que el segundo describe los campos que se mostrarán (o proyectarán; estos términos son intercambiables).

Para listar todos los documentos de la colección personas, contenida en la base de datos prueba, hemos tenido ya la ocasión de utilizar el método find, sin pasarle ningún argumento. En la práctica, devuelve lo que llamamos un cursor. De forma predefinida, un cursor está formado por grupos de 20 documentos. Cuando se realice una búsqueda que devuelva más de 20 documentos a través del shell de MongoDB, se tendrá que teclear it (de iterar) para acceder a los 20 resultados siguientes, hasta que el cursor haya sido recorrido por completo. Afortunadamente, se puede cambiar esta limitación utilizando la API config. Por ejemplo, si se desea que los cursores muestren grupos de 40 documentos, todo lo que se tiene que hacer es escribir:

config.set("displayBatchSize", 40) 

El cambio surtirá efecto inmediatamente y persistirá incluso cuando se conecte al shell en el futuro.

Ahora vamos a crear una nueva versión de nuestra colección...

Operadores de comparación

Ahora vamos a realizar consultas en el único campo de tipo entero de nuestros documentos: el campo edad.

Si queremos mostrar las personas cuya edad es exactamente 76, podemos ejecutar la siguiente consulta:

db.personas.find({"edad": 76}) 

Pero también podemos utilizar el operador de igualdad $eq para solicitar una igualdad estricta:

db.personas.find({"edad": {$eq: 76}}) 

La primera forma es mucho más fácil de leer, pero el resultado es exactamente el mismo. La única diferencia radica en la forma de escribir la igualdad. En el segundo caso, tenemos un documento que a su vez contiene un documento cuya clave es el operador de igualdad $eq y cuyo valor es el número 76.

Si queremos obtener los nombres de las personas de 76 años, utilizaremos la parte de proyección de nuestro método de búsqueda find enumerando los campos que queremos que aparezcan en pantalla. El documento tendrá una clave llamada nombre y un valor booleano cuyo valor será true.

db.personas.find({"edad": {$eq: 76}}, {"nombre": true}) 

La ejecución de esta consulta muestra que efectivamente se muestra el campo nombre, pero también el identificador ObjectId de cada documento. Simplemente se indicará que no se desea conservar poniendo el valor booleano false delante del nombre del campo...

Operadores lógicos

1. El operador $and

El operador $and (Y) se utiliza para unir estos dos documentos. Su sintaxis es:

{$and: [{criterio1}, {criterio2}, ...]} 

Si reescribimos nuestra condición de filtro, obtenemos:

{$and: [{"edad": {$exists: 1}}, {"edad": {$nin: [70, 80]}}]} 

Nuestros criterios se enumeran ahora en una matriz a la que se aplicará una sucesión de «AND» lógicos. Ya podemos escribir la versión final de nuestra consulta:

db.personas.find({  
 $and: [{  
   "edad": {  
     $exists: 1  
   }  
 }, {  
   "edad": {  
     $nin: [70, 80]  
   }  
 }]  
}, {  
 "_id": 0  
 "nombre": 1  
 "apellido: 1  
}) 

Sin embargo, en el caso de un AND simple como el que acabamos de realizar, es mejor utilizar el AND implícito, enumerando nuestros criterios uno tras otro:

db.personas.find( 
 "edad: {  
   $exists: 1  
   $nin: [70, 80]  
 } 
}, {  
 "_id": 0  
 "nombre": 1  
 "apellido:...

Otros operadores

1. El operador $expr

Introducido en la versión 3.6, $expr permite utilizar expresiones en las consultas. Estas expresiones pueden contener operadores, objetos o rutas que apunten a campos.

A continuación, vamos a mostrar los nombres de las personas cuya longitud del apellido (en caracteres) multiplicada por 12 sea mayor que su edad. Nuestro find primero filtra la presencia obligatoria de los campos apellido y edad porque, como nuestra expresión va a operar sobre ellos, queremos asegurarnos de que están disponibles. A continuación, utilizamos el operador $strLenCP, que trabajará sobre el valor contenido en el campo apellido de cada documento en el que esté presente. Se comprobará entonces para cada documento si el producto de la longitud del apellido por 12 da un número superior al valor contenido en el campo edad. Esta notación con el signo del dólar ($) rodeado de comillas se conoce como field path, y apunta a los valores contenidos en los campos del documento que se está procesando. Es el equivalente al puntero this seguido del nombre de uno de sus miembros de datos en muchos de los lenguajes de programación orientados a objetos.

db.personas.find({  
 "apellido": { $exists: 1 },  
 "edad": { $exists: 1 } 
 $expr: { $gt: [ { $multiply: [{ $strLenCP: "$apell" }, 12]}, 
"$edad"]} 
 },  
 {"_id":0, "apellido":1}  
) 

Vamos a crear una nueva colección llamada banco para utilizar $expr en un nuevo contexto. Esta colección contiene cuatro documentos con un campo numérico crédito obligatorio y un campo débito opcional. Aquí está el comando para crearla:

db.banco.insertMany([  
   {"_id": 1, "crédito": 2000, "débito":[1000, 22, 50]},  
   {"_id":...

Operadores para matrices

Añadir valores a una matriz utilizando $push

Este operador nos permite añadir (literalmente, «empujar»; push) uno o más valores a una matriz. Su sintaxis es muy intuitiva:

{ $push: { < campo >: < valor >, ...} } 

El operador $push tiene un inverso, muy lógicamente llamado $pull, que tiene exactamente la misma sintaxis.

Vamos a crear una colección de aficiones para practicar e insertar algunos documentos:

db.aficiones.insertMany([  
 { "_id": 1, "nombre": "Yves"},  
 { "_id": 2, "nombre": "Sandra", "aficiones": []},  
 { "_id": 3, "nombre": "Line", "aficiones": ["Teatro"]}  
]) 

A Yves también le apasiona el senderismo:

db.aficiones.updateOne({"_id": 1}, {$push: {"aficiones": "Senderismo"}}) 

El campo no existía en el documento identificador 1, por lo que se creó y se añadió su elemento único «Senderismo».

Line ha descubierto su pasión por la natación; sin embargo, ya tiene otra pasión, así que la actualización consistirá en añadir un nuevo elemento a su tabla: 

db.aficiones.updateOne({"_id": 3}, {$push: {"aficiones": "Natación"}}) 

Tras dos intentos en la piscina, Line se dio cuenta de que era alérgica al cloro, así que la natación no iba a ser una de sus pasiones:

db.aficiones.updateOne({"_id": 3}, {$pull: {"aficiones": "Natación"}}) 

Sandra, que hasta ahora no era una persona muy entusiasta, de repente se ha enamorado del dibujo y la pintura; así que vamos a añadir dos elementos a la vez, y para ello tendremos que utilizar el modificador $each:

db.aficiones.updateOne({  
    "_id: 2  
}, {  
    $push: {  
      "aficiones": {  
        $each: ["Dibujo", "Pintura"]  
      }  
    }...

Clasificar

La clasificación se realiza mediante el método sort, que se aplica a un cursor, de la siguiente manera:

cursor.sort(< clasificación >) 

El parámetro de clasificación es un documento que describe la ordenación que se va a realizar. Hay dos tipos de ordenación: ascendente (denotado 1) y descendente (denotado -1). Para clasificar nuestra colección de alumnos en orden ascendente de nombre, vamos a ejecutar la siguiente consulta:

db.alumnos.find({}, {"_id": 0, "apellido": 1}).sort({"apellido": 1}) 

Para ordenar primero en orden ascendente el apellido y luego en orden descendente el nombre, tenemos que modificar ligeramente nuestro documento de ordenación:

db.alumnos.find({},{"_id":0, "apellido": 1,  
      "nombre": 1}).sort({"apellido": 1, "nombre": -1}) 

Es perfectamente posible ordenar por los valores contenidos en los documentos. Para nuestra colección de alumnos, podríamos pedir una ordenación descendente sobre la primera nota obtenida en la tabla calif:

db.alumnos.find({},{"_id": 0, "apellido": 1, "nombre":  
1}).sort({"calif.0.nota": -1}) 

También podemos utilizar el método limit junto con sort para limitar el número...