DEV Community 👩‍💻👨‍💻

Natalia Venditto
Natalia Venditto

Posted on

Bases de datos: operar con la base de datos - parte 2

En la entrada anterior aprendimos cómo crear una base de datos y una colección, y también empezamos a trabajar con la base de datos usando las operaciones CRUD para crear documentos.

Al final de la entrada, les recomendé utilizar el comando mongoimport de las herramientas de base de datos, para importar un set o conjunto de datos más extenso, y así poder trabajar con MQL de manera más compleja.

Si no lo hicieron, les recomiendo ir a la entrada 3 y seguir las instrucciones.

Operaciones CRUD para leer documentos

Hoy vamos a aprender a usar MQL, el lenguaje de consultas de MongoDB para, justamente, consultar nuestra base de datos de redtatuaje.

Como aprendimos en la entrada anterior, vamos a usar la terminal para conectar a nuestro servidor local, y usar la base de datos deseada y colección, deseadas.

conectar a mongodb servidor local

Operación CRUD findOne()

Lo primero que vamos a hacer es inspeccionar cualquier documento de la base de datos, de manera aleatoria, solo para ver qué estructura tiene un documento.

Lo haremos ejecutando primero, como aprendimos antes, show collections para ver qué colecciones tenemos disponibles y asegurarnos que hemos importado correctamente los datos, para poder seguir las indicaciones de esta entrada.

mostrar las colecciones mongodb

y luego ejecutando

db.artistas.findOne()
Enter fullscreen mode Exit fullscreen mode

mongodb metodo findOne()

findOne() devuelve el primer documento que encuentra, que satisface un determinado criterio de consulta, es decir, el primero a partir del orden natural en el que se encuentran los documentos. Si la colección tiene un límite de algún tipo (generalmente en MB), entonces el orden natural corresponde al orden de inserción. En este caso vemos que devuelve el correspondiente al artist_id: 743 correspondiente al name: "Alex Holt".

Parámetros opcionales de findOne()

El método findOne() acepta que se le pasen dos argumentos opcionales para determinar ese criterio. Por ejemplo, podemos decir

db.artistas.findOne(query, projection)
Enter fullscreen mode Exit fullscreen mode

la consulta en sí, y una condición de proyección.

Si vemos la imagen anterior, podemos comprobar que para el artista de id 743, la propiedad owns_studio, tiene el valor Yes. Podemos pedir a MongoDB que nos devuelva el primero por orden natural, para que ese valor sea No.

db.artistas.findOne({ "owns_studio": "No"})
Enter fullscreen mode Exit fullscreen mode

findOne() pasandole una consulta

En cuyo caso, como podemos ver, el id de artista es ahora 701, correspondiente a la artista de name: "Sue King".

Proyección de consultas (Projection)

Pero hemos dicho que este método además aceptaba un segundo parámetro adicional, de proyección. ¿Qué significa eso?

MongoDB siempre va a devolver los campos de un documento que se encuentran proyectados. Por defecto, todos los campos están proyectados, o sea tienen el valor de proyección a 1 o true.

1 u otros valores diferentes de 0 y true, especifican inclusión en la proyección

Sin embargo, si explícitamente proyectamos un campo, solo se devolverá ese campo junto con el valor del _id, que solo se excluye si se pone su valor de proyección explícitamente a 0 o false.

Veamos un ejemplo

db.artistas.findOne({ "owns_studio": "No"}, {"owns_studio": 1, "name": 1})
Enter fullscreen mode Exit fullscreen mode

findOne() con consulta y proyección

Si queremos omitir el valor del campo _id, le tenemos que pasar 0 explícitamente (o false)

db.artistas.findOne({ "owns_studio": "No"}, {"owns_studio": 1, "name": 1, "_id": 0})
Enter fullscreen mode Exit fullscreen mode

exluir el _id en la proyección Mongodb

Vamos a ver a estudiar Projection más adelante en la serie con más profundidad, ya que hay muchísimas más formas de proyectar, y formas especiales para datos más complejos, como los datos anidados, o los arreglos.

Operación CRUD find()

Hasta ahora, como pedíamos MongoDB encontrar uno, o findOne(), siempre devolvía solo uno...Pero, ¿qué pasa cuando queremos una lista?

Entonces debemos ejecutar

db.artistas.find()
Enter fullscreen mode Exit fullscreen mode

Pero espera...¿Qué ha pasado? ¿Nos ha devuelto los 1000 documentos que habíamos importado a la colección?

No. Este método devuelve un cursor, que es una referencia a un conjunto de resultados que devuelve una consulta, y que se pueden iterar. Es decir, podemos ver más de lo que hay en el cursor y luego acceder al documento que deseamos.

Por defecto el cursor para find() nos muestra 101 resultados siempre que no se exceda el máximo tamaño de documento, que es de 16MB (como ya vimos en la entrada 1 de la serie) y una de las formas de obtener más es ejecutando it, como vemos en la imagen.

iterar el cursor en mongoDB

También podemos asignar el cursor a una variable (¡recordemos que estamos en un REPL completamente funcional!) y utilizar algunos de sus métodos. Por ejemplo.

let tatuadores = db.artistas.find({ "owns_studio": "Yes" });

while (tatuadores.hasNext()) { 
  printjson(tatuadores.next());
}
Enter fullscreen mode Exit fullscreen mode

Aquí estamos usando los métodos hasNext() que evalúa si hay más documentos que satisfagan la consulta, en el cursor, y utilizamos el método next(), para iterarlos mientras hasNext() devuelva true.

Otros métodos del cursor son forEach(), toArray() y objsLeftInBatch(), que nos dice cuántos objetos hay en el batch, después de ejecutar una iteración (o conjunto) devuelto.

Podemos también utilizar el método isExhausted() para comprobar que realmente no existen más objetos o documentos, en el cursor.

Recordemos que cada documento mapea a un objeto.

Una lista completa de métodos del cursor, se pueden encontrar aquí

Cuando se usaba find() con las versiones anteriores de la consola, se solía concatenar el método pretty(), para que los resultados en el cursor se mostrasen formateados. En mongosh, pretty() se ejecuta por defecto.

Veamos un ejemplo de usar forEach():

let tatuadores = db.artistas.find({ "owns_studio": "Yes" });

tatuadores.forEach((tatuador) => { 
  if (tatuador.payment_method === "Credit Card Only") { 
    printjson(tatuador);
  }
});
Enter fullscreen mode Exit fullscreen mode

Limitar el cursor a una cantidad específica de resultados en el batch

En una base de datos muy grande, con documentos de tamaño muy pequeño, podríamos tener demasiada cantidad de objetos devueltos. Si queremos limitarlos de manera explicita para aumentar el rendimiento, podemos usar el método limit(), de esta manera.

db.artistas.find({"payment_method" : "Credit Card Only"}).limit(5)
Enter fullscreen mode Exit fullscreen mode

Más información sobre el método limit() se encuentra aquí.

Parámetros opcionales de find()

Find también acepta la configuración de dos parámetros opcionales: la consulta y la proyección.

Consultas complejas con operadores de consulta

Vamos a empezar a realizar consultas más complejas, utilizando los operadores de comparación. En otras entradas exploraremos los lógicos, de elemento, de evaluación, de array y geoespaciales. Y por supuesto, haremos una entrada específica sobre proyección.

¡Empecemos!

Encontrar un valor equivalente al pasado en la consulta: operador $eq

Este operador nos permite consultar la base de datos para encontrar todos los documentos que tienen un valor especifico que equivale al que se pasa. Por ejemplo, vamos a buscar todos los artistas que no tienen estudio propio.

Vamos a limitar las consultas siempre a 5 para reducir el tiempo de respuesta, pero eso no es un requerimiento.

db.artistas.find({ "owns_studio": { $eq: "No" } }).limit(5)

Enter fullscreen mode Exit fullscreen mode

El formato de la consulta es:

{ <campo>: { $eq: <valor> } }
Enter fullscreen mode Exit fullscreen mode

Podemos decir que esto es equivalente a realizar esta consulta

db.artistas.find({ "owns_studio": "No" }).limit(5)

Enter fullscreen mode Exit fullscreen mode

sin embargo, al usar operadores, los podemos combinar o usar operadores lógicos, para consultas más complejas, como veremos mientras progresemos.

Encontrar un valor más grande que el valor pasado: operador $gt

Este operador nos permite encontrar los documentos para los cuales el valor del campo pasado, es más grande que el especificado. En este caso, todos los artistas con un identificador más grande que 500

db.artistas.find({ "artist_id": { $gt: 500 } }).limit(5)

Enter fullscreen mode Exit fullscreen mode

El formato de la consulta es:

{ <campo>: { $gt: <valor> } }
Enter fullscreen mode Exit fullscreen mode

Igualmente podemos encontrar valores más grandes o iguales al valor pasado, con $gte, más pequeños con $lt, o más pequeños o iguales al valor pasado, con $lte. La sintaxis es la misma.

Encontrar todos los valores diferentes a: operador $ne

ne vendría a significar not equal, o no igual. Lo usamos para encontrar todos los documentos cuyo valor no es igual al pasado.

db.artistas.find({ "artist_id": { $ne: 500 } }).limit(5)

Enter fullscreen mode Exit fullscreen mode

Por supuesto que no necesariamente estamos haciendo comparaciones numéricas. Estamos comparando valores literales. Por lo cual, podemos pasar cualquier tipo.

db.artistas.find({ "name": { $ne: "Cordelia Swanson" } }).limit(5)

Enter fullscreen mode Exit fullscreen mode

Y esto es cierto para las comparaciones de arriba, también. Por ejemplo:

db.artistas.find({ "country": { $lt: "PE" } }).limit(5)
Enter fullscreen mode Exit fullscreen mode

Donde devolverá todos los valores más pequeños que "PE" como código de país, en orden alfabético.

Comparar fechas con operadores de comparación

También los podemos usar para las fechas. Por ejemplo, si queremos encontrar a todos los artistas que se unieron a la plataforma hace un año o más, lo haríamos así:

db.artistas.find({ "joined_network": { $lte: new Date("2021-08-12") } }).limit(5)
Enter fullscreen mode Exit fullscreen mode

Excluir resultados que contengan un valor en un campo array: operador $nin

Este operador not in, nos permite excluir objetos del cursor, sí contienen un cierto valor en un campo de tipo arreglo.

Por ejemplo, supongamos que queremos filtrar a todos los artistas que se dedican a los estilos geometric y realism, de nuestro cursor de resultados.

db.artistas.find({ "styles": { $nin: ["geometric", "realism"] } }).limit(10)

Enter fullscreen mode Exit fullscreen mode

$nin también puede usarse para excluir del cursor los documentos que no contienen un cierto campo.

Más información sobre este operador de condición, se encuentra en la documentación

MQL en el mongosh vs. operar con un driver

No se debe confundir los métodos de operación de MQL en la consola de MongoDB, con los métodos que provean los diferentes drivers cuando se está escribiendo una aplicación.

Muchos de estos drivers (o software intermedio) crean capas de abstracción para simplificar la combinación de operadores, y es posible que ofrezcan diferentes métodos para operar con la base de datos.

En la próxima entrada, vamos a usar operadores lógicos. ¡Hasta entonces!

Gracias especiales a @wassimchegham que siempre me revisa los screenshots y a @dfreniche al que le pedí peer review, y me contesto "RIGHT NAO!" <3

Top comments (0)

🤯

"I made 10x faster JSON.stringify() functions, even type safe"

☝️ Must read for JS devs