Bases de datos: operar con la base de datos - parte 1
Published: 2022-08-03 17:58:36

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](https://www.mongodb.com/try/download/community) 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](https://www.mongodb.com/products/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](https://www.mongodb.com/try/download/shell). Una vez está instalada, la arrancamos así

```
mongosh
```

![conexion mongosh a mongodb](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k6wdne1qi5an44vy8u0x.png)

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`.

![show dbs mongodb](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0b4qxb5fr5zdzm2cmu6y.png)

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.


![mongodb comando use](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m102obedv6bo08fjwgop.png)

Pero...qué pasa si ejecuto `use`, con una base de datos que no existe. Vamos a verlo...

```
use Item
```

![mongodb comando use](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0mxh2xnikapg4lhzsjb.png) 

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**_


![mongodb comando use db vacia](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1kn4yk59v8l8gky0458i.png)

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.


![mongodb comando use](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bd3jmp771rt86anp0ct9.png)

## `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
```

![mongodb show collections](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvfbe3jqc1vyw3j2lt7q.png)

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")
```

![mongo db create collection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpyv8efkx0ie9di3xs05.png)

_Nota: métodos adicionales se pueden encontrar en la [documentación oficial](https://www.mongodb.com/docs/manual/reference/method/js-database/)_

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 


![mongodb show collection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vslodvlv4cd48kqa4cd9.png)

> _**¡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](https://www.mongodb.com/docs/manual/reference/method/js-collection/)

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.


![mongo db show collection colección vacia](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j1zkkxqdfhs308zkgt0i.png)

> _**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 tipo `ObjectId` se auto-indexa y es clave primaria de cada colección._**

Si ahora ejecutamos el método `findOne()`, podemos ver la estructura del documento.

![mongodb](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkvhi0lf1jd2cd2rzbb6.png)


## 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([{},{},{}])
```

![mongodb insertando documentos](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ta2mmv54tbt8z3karg4z.png)

_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)
```

![mongodb update document](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xr569hq1zj9ewwj68gs.png)


![mongodb update document](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuk3sdd95elmmrg90giw.png)

> **_Por cierto, cuando hablamos en la jerga de MongoDB en inglés, los métodos que tienen un `$` antes del nombre, se suelen decir como `dollar-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 })
```

![mongodb update document](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vq6rb3elocz7gsldl3l.png)

Otras opciones que recibe este método, se pueden aprender [aquí](https://www.mongodb.com/docs/manual/reference/method/db.collection.updateOne/)

### 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](https://www.mongodb.com/docs/manual/reference/insert-methods/), y más métodos adicionales de actualización, se explican [aquí](https://www.mongodb.com/docs/manual/reference/update-methods/)

## ¿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, **<u>no es recomendable desde el punto de vista funcional que los documentos de una misma colección tengan campos totalmente diferentes</u>**, 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](https://www.mongodb.com/docs/database-tools/installation/installation/)

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](https://github.com/anfibiacreativa/atlas-serverless). Básicamente lo que van a necesitar hacer es importar [este archivo](https://github.com/anfibiacreativa/atlas-serverless/blob/develop/database_exports/tattoonetwork/artists.json) que es un listado de artistas de tatuaje (¡que no existen! los generé con [mgeneratejs](https://www.npmjs.com/package/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](https://github.com/anfibiacreativa/atlas-serverless/blob/develop/database_exports/tattoonetwork/artists.json) 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](https://code.visualstudio.com/docs/azure/extensions), o desde el portal de Azure. 


![crear servidor cosmos db desde vs code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q81lldjnqehry8741o4x.png)

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) 


![copiar cadena de conexión cosmosdb mongodb api](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4cfijn1wnzzqpsji11q7.png)


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í](https://www.mongodb.com/docs/manual/reference/connection-string/)

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!