En las entradas anteriores hablamos del modelo de documento y del particionamiento de bases de datos distribuidas, que corresponden a ese modelo. ¡Llegó el momento de trabajar un poco con las mismas!
Pre-requisitos
Para poder experimentar deberán tener instalado MongoDB Community Server y las herramientas de terminal y extensiones necesarias. Pueden ir a la primera entrada de esta serie, para encontrar indicaciones. También pueden instalar Compass, la herramienta gratuita de Interfaz Gráfica Visual de MongoDB.
Crear una base de datos MongoDB desde la terminal
Vamos a empezar trabajando con la Mongo Shell. Una vez está instalada, la arrancamos así
mongosh
Eso nos conecta directamente a nuestro servidor local, lo cual podemos apreciar en la imagen, ya que al ejecutarlo se inicia una conexión a 127.0.0.1:27017
o sea a la IP de bucle invertido, o localhost
en el puerto 27017
que es el puerto que usa mongod
(o sea el proceso mongo daemon del que hablamos en la primera entrada de la serie) por defecto. Además inicializa el entorno REPL JavaScript (read-evaluation-print loop o bucle de lectura, evaluación y salida).
Más adelante conectaremos a un despliegue remoto, para lo que necesitaremos usar una cadena de conexión pero por ahora trabajaremos en local.
Mostrar las bases de datos existentes: show dbs
Para ver las bases de datos que existen en nuestro servidor vamos a usar el comando show
. Simplemente escribimos en la terminal show dbs
.
Cuando se instala un servidor, MongoDB crea algunas bases de datos que utiliza el sistema para operar, como admin
, config
y local
.
Nota: No se recomienda manipular las bases de datos por defecto, ya que puede alterar el correcto funcionamiento del sistema.
El comando use
Para cambiarnos de base de datos usamos el comando use
, al que le pasamos el nombre de la base de datos que queremos utilizar.
En mi caso ya tengo una base datos adicional que se llama Items
de modo que si ejecuto
use Items
el sistema va a usar esa base de datos, como se ve en la captura.
Pero...qué pasa si ejecuto use
, con una base de datos que no existe. Vamos a verlo...
use Item
En este caso el sistema creará una referencia a una base de datos de ese nombre.
¡Pero cuidado! Mientras esa base de datos esté vacía, no será listada, como podemos ver en la siguiente captura
Hay que tener cuidado con la puntuación, entonces, porque si estamos trabajando con la base de datos Items
y nos equivocamos y escribimos Item
, estaremos creando esa base de datos nueva. ¡Con las colecciones, pasa lo mismo! Esto es el comportamiento por diseño de MongoDB y por eso, para evitar operar con una base de datos o colección incorrecta cuando usamos los drivers desde una aplicación, hay que seguir buenas prácticas que nos eviten dolores de cabeza, como por ejemplo asignar esos nombres a constantes.
Cuando usamos use
, entonces, lo que hacemos es asignar un valor al objeto db
que ahora apuntará a una base de datos en concreto. Si simplemente ejecutamos db
, nos dirá cuál es ese base de datos.
show collections
para mostrar colecciones
Para saber qué colecciones existen en una base de datos una vez que la estamos usando, ejecutamos show collections
en la misma.
show collections
Dado que Item
no tiene ninguna colección, no devuelve nada. Así que vamos a crear una colección. Podemos usar el método createCollection()
del objeto db.
db.createCollection("items")
Nota: métodos adicionales se pueden encontrar en la documentación oficial
Podemos ver que al ejecutar show collections
, nos muestra la colección items
que existe en nuestra base de datos activa.
También podemos ejecutar
db.[nombre_de_collección]
Por ejemplo
¡A prestar atención! Porque hemos escrito
item
como nombre de colección. Dado que no existe, MongoDB la creará.
Operaciones CRUD para operar con documentos
Para demostrar este último concepto, vamos a utilizar nuestro primer operaciones CRUD, a nivel colección. Podemos encontrar un listado completo de los mismos en la documentación
Hasta ahora tenemos una colección llamada items
. Cuando ejecutamos show collections
, es la única que aparece. Pero si ejecutamos
db.item.insertOne({})
y luego ejecutamos show collections
, veremos que ahora que hemos insertado un documento vacío, entonces aparecen ambas colecciones.
Lo importante a tener en cuenta, es que por diseño MongoDB creará una base de datos o colección que no existe, si se opera con las mismas.
Hemos por fin ejecutado nuestra primera operación CRUD para crear un documento nuevo. Dado que le hemos pasado un objeto vacío {}
al método, el documento está vacío a excepción del identificador de tipo ObjectId
que MongoDB asigna automáticamente a todos los documentos. Más adelante en la serie cuando hablemos de indexes (indíces) explicaremos más sobre el campo _id
y cómo puede customizarse según las necesidades de nuestra aplicación, ya que este campo siempre se indexa como clave primaria de una colección.
El campo automático
_id
o identificador único de documento, de tipoObjectId
se auto-indexa y es clave primaria de cada colección.
Si ahora ejecutamos el método findOne()
, podemos ver la estructura del documento.
Operaciones CRUD
Las operaciones CRUD (create, read, update, delete en Inglés) nos permiten operar con la base de datos para crear, leer, actualizar y borrar datos o documentos, en la base de datos.
Cuando operamos con la base de datos, generalmente usamos una o una combinación de éstas operaciones convencionales.
Vamos a empezar con las operaciones que crean documentos.
Creación de documentos
Como ya pudimos observar anteriormente, podemos crear un documento a través del método insertOne( {<documento>} )
, al que pasamos un objeto que representa el documento. Si no pasamos ninguna propiedad, se creará un documento vacío, con un identificador único.
db.[nombre-de-colección].insertOne({ "nombre": "Documento1", "estaEscrito": true })
Además de insertOne()
al que pasamos un solo objeto, podemos utilizar insertMany()
para insertar múltiples documentos en la base de datos por medio de un arreglo.
Para probarlo, vamos a ejecutar
db.item.insertMany([{},{},{}])
Tengan en cuenta que obviamente, los identificadores que se generarán en la ejecución de ustedes, serán otros.
Ahora vamos a actualizar uno de estos documentos de la colección, utilizando updateOne()
. Este método espera recibir una condición para filtrar el documento deseado (en nuestro caso sólo podemos pasarle el _id
, y un objeto con el campo que se va a modificar, que se pasa al método $set
, así:
db.item.updateOne({ "_id": ObjectId("62e7f362b654003b0ba25e4a")}, // esto es el filtro que encuentra el documento a actualizar {$set: {"campo_nuevo": true}} // $set le agregará el campo_nuevo, o lo actualizará si existiera)
Por cierto, cuando hablamos en la jerga de MongoDB en inglés, los métodos que tienen un
$
antes del nombre, se suelen decir comodollar-nombre
. En este caso, se leerádollar-set
.
También podemos pasar upsert
como parámetro adicional del objeto options
que recibe opcionalmente este método, lo que garantizará que si el filtro no encuentra ninguna correspondencia, se creará el documento. Para demostrarlo, le cambiamos los 4 últimos dígitos a cualquiera de los ids que nos devuelva por 0000
(¡a menos que ya exista uno que termine con 0000! Entonces elegiremos 4 cifras que no existan. 😅)
db.item.updateOne({ "_id": ObjectId("62e7f362b654003b0ba20000")}, {$set:{"campo_nuevo": true}},{ upsert: true })
Otras opciones que recibe este método, se pueden aprender aquí
Más métodos que crean documentos
Otros métodos que crean documentos cuando se les pasa la opción upsert
a true
, se especifican en está página, y más métodos adicionales de actualización, se explican aquí
¿Documentos con estructura diferente?
Se dieron cuenta, ¿verdad? Al haber actualizado un par de los documentos, existen documentos en una misma colección, con una estructura distinta. Esto es perfectamente posible en MongoDB y el modelo documento, porque aunque se puede implementar un schema
y proceder a la validación de datos a través del mismo, no es obligatorio tenerlo. Sin embargo, no es recomendable desde el punto de vista funcional que los documentos de una misma colección tengan campos totalmente diferentes, aunque está cualidad permite agregar campos a ciertos documentos de la colección, sin tener que nulificar
(o para no inventarme términos raros, dar un valor null
) al mismo campo en aquellos documentos para los que no existe el valor -o la propiedad no aplica-. Esto puede ser útil para ciertos casos de uso, en el modelado de datos.
Existen documentos en esta colección con una estructura distinta. Esto es perfectamente posible en MongoDB y el modelo documento, porque aunque se puede implementar un
schema
y proceder a la validación de datos a través del mismo, no es obligatorio tenerlo.
Utilizar mongoimport
para importar datos a una base de datos MongoDB
Para poder hacer uso de esta utilidad, tendremos que haber instalado las herramientas de base de datos
como se indica en este documento
Además, pueden forkear
(me encanta escribir entradas en español y darme cuenta que no tengo ni idea de cómo traducir algunas operaciones de GIT. ¡Espero no ofender a nadie!) este repo. Básicamente lo que van a necesitar hacer es importar este archivo que es un listado de artistas de tatuaje (¡que no existen! los generé con mgeneratejs).
Antes que nada, vamos a poner en uso algunos de los conceptos que aprendimos antes para crear una base de datos que se llame redtatuaje
y una colección que se llame artistas
.
A la misma le vamos a importar este archivo abriendo una nueva pestaña de la terminal (o ventana, según el caso -ojo! no mongosh o mongo, sino bash/zsh, etc) y ejecutando
mongoimport --uri mongodb://localhost:27017 --db redtatuaje --collection artistas --file [ruta-al-archivo]/artists.json
El comando anterior asume que el servidor está corriendo en el puerto por defecto 27017. Recuerden que si no crearon la base de datos y colección con anterioridad, o si la escriben de manera diferente (intencionalmente o por error), se crearán.
Conectando a una base de datos remota
mongoimport
y el resto de utilidades, se pueden usar también para operar con bases de datos remotas. Por ejemplo supongamos que tenemos un servidor Cosmos DB que creamos para usar con MongoDB API. Lo podemos crear directamente desde VS Code, con la extensión de Azure Tools, o desde el portal de Azure.
Una vez creado, podemos obtener la cadena de conexión desde la extensión de VS Code directamente, haciendo click con el botón derecho del ratón para desplegar el menú, y luego haciendo click en Copy connection string
(obtener cadena de conexión)
o yendo a la página de configuración del recurso y copiando o pegando la cadena de lectura + escritura
, en este caso, ya que vamos a crear documentos.
Más sobre la cadena de conexión MongoDB
Una cadena de conexión es precisamente una concatenación de argumentos que nos permiten establecer la conexión, y que en el caso de la de MongoDB, se compone del protocolo, que en el caso de MongoDB puede ser mongodb
o mongodb + srv
, el dominio de servidor (o IP) que se corresponde al parámetro host
, con su respectivo puerto
, el nombre de usuario o cuenta, la contraseña y algunos parámetros adicionales de configuración, como por ejemplo si utilizaremos ssl
, el nombre del conjunto de réplicas y si se intentará reescribir en caso de errores de conexión o retardos.
La cadena de conexión es la concatenación de argumentos que nos permiten establecer la conexión con la base de datos, a la vez que configuramos ciertos aspectos de la misma.
Lo que vamos a hacer es copiar exactamente el comando de arriba, y reemplazar el valor de la opción --uri
que ahora apunta a localhost, por la cadena de conexión tal cual la obtuvimos del portal o la extensión de VS Code, puesta entre comillas.
mongoimport --uri "[cadena-de-conexión]" --db redtatuaje --collection artistas --file [ruta-al-archivo]/artists.json
Eso nos permitirá importar los datos desde el archivo en nuestro ordenador local, para poder trabajar con los mismos en remoto.
Más información sobre la cadena de conexión, la podemos leer aquí
Ahora ya tenemos todo listo para consultar documentos locales o remotos de manera eficiente con MQL. ¡Nos vemos en la próxima entrada donde vamos a aprender a hacerlo!
¡Hasta la próxima!
Top comments (1)
Ey Natalia!!
¡Vuelvo a alucinar con tus post! 🙌
Gracias por hacerlo todo tan fácil, por detallar cada uno de los conceptos que explicas para que parezca más sencillo 🙏
Sabes? Además de profesionalidad tu orden y presentación transmite paz y tranquilidad (no me genera estrés leerte) y eso me gusta mucho! No es fácil, créeme.
Mucho ánimo y buena onda para que esto no acabe 😉🙋🏻♂️