¡Hasta -30% en todos los libros en línea,
eformaciones y vídeos*! Código: NEURONA30 Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros y videos
  2. MongoDB
  3. Introducción
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

Introducción

Big Data y NoSQL

Hace ya algunos años que el término Big Data entró en el lenguaje común, tal es el grado en que los datos se han convertido en algo tan central en nuestras vidas. Ya se trate de nuestros historiales médicos, nuestras cuentas bancarias, nuestras compras en línea o nuestra actividad diaria en las distintas redes sociales, a diario se transmiten volúmenes gigantescos de datos por todo el planeta.

El Big Data debe afrontar el reto de analizar y explotar estos enormes volúmenes de datos para hacerlos útiles y, seamos sinceros, a menudo monetizables: el recorrido de un cliente en un sitio de venta al menudeo, la publicidad dirigida que podría desencadenar una compra por su parte, los últimos vídeos que ha visto para que se le puedan sugerir otros que podrían gustarle, las palabras clave y los temas demoda (trending topics) en su red social favorita...

Para dar sentido a toda esta información, se necesitan bases de datos capaces de almacenar y procesar muy rápidamente la materia prima que son estos datos brutos, cuya naturaleza es, cuando menos, heterogénea (flujos de vídeo o audio, texto plano, datos de geolocalización, imágenes, etc.). A este respecto, el modelo de base de datos relacional, que durante mucho tiempo reinó en el desarrollo informático, mostró rápidamente sus limitaciones debido...

MongoDB

Lanzada al mercado hace quince años y disponible actualmente en su versión 8.0, MongoDB es una base de datos «orientada a documentos». Esto significa que la unidad ya no es la tupla (o fila) como en el modelo relacional, sino el documento. A diferencia del registro contenido en una tabla de una base de datos relacional, el documento no tiene una estructura fija y predecible. Dos documentos pueden contener los mismos campos, pero en un orden completamente distinto, lo que es inconcebible en el paradigma relacional, donde las tablas son como moldes en los que se «funden» los registros. En una tabla que contenga información sobre personas, todos los campos deben contener un valor de un tipo predefinido (o el marcador NULL, que indica la ausencia de cualquier valor) y aparecer en el mismo orden. En un documento, un campo sin valor puede simplemente estar ausente, mientras que en una tabla se le asignará obligatoriamente el marcador NULL. Así es como la estructura matricial de una tabla en el paradigma relacional se contrapone a menudo a la propia ausencia de estructura en una base de datos NoSQL.

En una base de datos relacional, el esquema (o intención) describe la estructura que deben respetar todas las tuplas (o filas) de las tablas que componen la base de datos. En una base de datos orientada a documentos, puede haber tantos formatos de datos como documentos. Se dice que estas bases de datos...

Componentes de MongoDB

Puede desplegar MongoDB en una o varias máquinas de su empresa, instalarlo en su ordenador personal como versión independiente (standalone) o utilizarlo sin instalar nada, utilizando soluciones desplegadas en la Nube, a través de los centros de datos (datacenters) de Amazon Web Services o Microsoft Azure o a través de Atlas, la solución DBaaS (database as a service) creada por MongoDB.

Los principales componentes de MongoDB son:

  • mongod, el programa principal. Gestiona el acceso a los datos y realiza operaciones de gestión de datos en segundo plano.

  • mongos, el enrutador que gestiona el encaminamiento de las consultas en un entorno distribuido. Cuando los datos se distribuyen en fragmentos (shards), es este proceso el que gestiona el acceso a los datos.

  • mongosh, el programa de línea de comandos para interactuar con la base de datos, al que nos referiremos en estas páginas como Shell (intérprete de comandos o línea de comandos). La interacción con la base de datos se lleva a cabo utilizando el lenguaje JavaScript, del que necesitará conocer los conceptos básicos.

Además, están los componentes de importación y exportación para BSON, un formato binario del que hablaremos en breve:

  • mongodump creará archivos que contengan el BSON presente en una base de datos.

  • mongorestore hará exactamente lo contrario, restaurar la información....

Arquitectura general de MongoDB

1. Escalado

Cuando hablamos de arquitectura de bases de datos, inevitablemente hablamos de despliegue, disponibilidad, replicación, tolerancia a fallos, recuperación de incidentes... y escalado (scaling). Una base de datos que se utilizará para realizar numerosas consultas deberá, tarde o temprano, hacer frente a la problemática de la escalabilidad; el servidor en el que reside está muy ocupado y vamos a tener que aumentar su capacidad de almacenamiento en memoria RAM;, se deberán añadir discos duros, procesadores, etc. Este aumento del rendimiento de un servidor mediante la adición de componentes de hardware se denomina escalado vertical (vertical scaling); debemos pensar en él como una pila sobre la que vamos a añadir componentes (discos, CPU, etc.). En oposición al escalado vertical, que alcanza rápidamente sus límites (¿hasta dónde podemos llegar para aumentar la capacidad de un único servidor?), se ha desarrollado el concepto de escalado horizontal (horizontal scaling), que consiste en distribuir enormes volúmenes de datos entre varias instancias de un gestor de base de datos, cada una alojada en una máquina dedicada. Ya no hablamos de un servidor monolítico que crece hasta alcanzar sus límites, sino de varios, cuyo número llega a ser prácticamente ilimitado, en los que se distribuyen los datos.

Esta partición de datos entre varias instancias, que permite el escalado horizontal, se conoce como sharding (fragmentación) en el universo MongoDB.

2. Principio de fragmentación (sharding)

La fragmentación (sharding) se realiza a nivel de una colección. Es esta colección la que se repartirá en varios fragmentos (shards) en función de un subconjunto de valores de un campo presente en todos los documentos de esta colección y que se utilizará como clave de fragmentación (shard key). Esta clave pivote está sujeta a ciertas restricciones: solo puede haber una clave de fragmentación por colección y su tamaño no debe superar los 512 bytes.

Esta clave no se podrá modificar una vez que la colección se haya...

Notación JSON

Esta notación en lenguaje JavaScript se utiliza para representar estructuras de datos, que a veces pueden ser bastante complejas, de una forma sencilla y legible por humanos. La interfaz de línea de comandos de MongoDB utiliza esta notación, así como JavaScript, por lo que es necesario dominar los conceptos básicos.

MongoDB almacena una representación binaria del formato JSON en un formato especialmente creado por sus diseñadores: BSON (por binary JSON). Cuando se interactúa con la base de datos, MongoDB transforma el código JSON que se proporciona en BSON, del mismo modo que transformará el BSON que se ha almacenado en JSON antes de presentárselo. El tamaño máximo de un documento en formato BSON está fijado en 16 MB, aunque es raro que un documento supere este límite (a modo de comparación, la versión en texto plano de la novela de Tolstoi Guerra y Paz tiene un tamaño de poco más de 3 megabytes... ¡y el libro tiene más de 1.200 páginas!)

Así se representa un objeto vacío en JSON:

{} 

Las propiedades de un objeto JSON se representan mediante uno o varios pares clave: valor, separados por una coma:

{"clave": "valor", "otra_clave": "otro_valor"} 

Un valor puede ser a su vez un objeto:

{"clave": {"otra_clave":...

Tipos de datos

JSON admite de forma integrada seis tipos de datos:

  • booleano

  • numérico

  • cadena de caracteres

  • tabla

  • objeto

  • null (marcador de ausencia de valor)

MongoDB añade sus propios tipos a estos tipos JSON predefinidos:

  • El tipo Date: se almacena como un entero con signo de 8 bytes que representa el número de segundos transcurridos desde la época Unix (01/01/1970 a medianoche).

  • El tipo ObjectId: almacenado en 12 bytes, se utiliza internamente para garantizar la unicidad de los identificadores generados por la base de datos, ¡por lo que su importancia es crucial!

  • Tipos enteros Long e Int32: se utilizan para representar enteros con signo representados internamente en 8 y 4 bytes respectivamente.

  • Tipo flotante Decimal128: codificado en 16 bytes, este tipo decimal de alta precisión se prefiere generalmente para aplicaciones que realizan cálculos matemáticos que requieren una alta exactitud.

  • El tipo BinData: se usa para almacenar cadenas de caracteres que no pueden representarse en codificación UTF-8 o cualquier contenido binario (volveremos sobre esto en la sección dedicada a GridFS).

  • Existen otros tipos; aquí hemos enumerado los más utilizados, pero encontrará una lista mucho más exhaustiva en: https://www.mongodb.com/docs/manual/reference/bson-types/

Usar MongoDB en la línea de comandos

1. Iniciar y detener MongoDB

Para iniciar MongoDB desde una terminal, simplemente ejecute mongod (o mongod.exe si utiliza Microsoft Windows). Este ejecutable tiene muchas opciones, y solo veremos las más importantes. Sin embargo, también se puede utilizar sin ninguna opción, simplemente ejecutando este comando:

mongod 

En la pantalla aparecen una serie de advertencias y una gran cantidad de información que no es necesario analizar en este momento. Echemos un vistazo a algunas de las opciones de este ejecutable:

  • port se utiliza para designar el número de puerto en el que escuchará el servidor. El valor predefinido para este número de puerto es 27017. Por lo tanto, el comando ejecutado anteriormente es equivalente a:

mongod --port 27017 
  • dpath es la opción utilizada para apuntar al directorio que contiene los datos. Así como una instancia dada debe apuntar a un único número de puerto (si está ejecutando dos mongods, se necesitará usar dos números de puerto separados, por ejemplo 27017 y 27018); también debe apuntar a un único directorio de datos. En GNU/Linux, este directorio se predefine a /data/db. Esto significa que el primer comando, sin ninguna opción, es en realidad equivalente a:

mongod --port 27017 --dbpath /data/db 
  • logpath se utiliza para redirigir cualquier salida de mongod a un archivo de registro ubicado en un directorio de su elección (asegúrese de tener acceso de escritura al directorio que especifique). Como este archivo de registro se sobrescribe cada vez que se inicia mongod, al añadir la opción logappend queremos decir que queremos añadir nuevos registros a los ya existentes y no reemplazarlos.

Este es el comando para hacerlo:

mongod --port 27017 --dbpath /data/db --logpath /tmp/mongodb.log  
--logappend 

Hay varias formas de detener MongoDB en GNU/Linux: simplemente pulsando Crtl+C, detener el servicio con sudo service mongodb stop si se instala MongoDB usando un gestor de paquetes, o ejecutando el siguiente comando en una nueva ventana de terminal:

mongosh --eval "db.getSiblingDB('admin').shutdownServer()" 

Aunque todas ellas son equivalentes, las dos últimas son las mejores formas de detener el servidor limpiamente y deberían preferirse a la primera, que sin embargo puede utilizarse cuando se desarrolla...

Gestionar colecciones

1. Intercalaciones

Las intercalaciones se utilizan para definir reglas de comparación de cadenas de caracteres, sobre todo en lo que respecta a la acentuación de los caracteres o sus mayúsculas y minúsculas en un idioma determinado. Las intercalaciones pueden utilizarse con colecciones, vistas o índices.

A continuación, se muestra un documento que contiene información sobre una intercalación:

{  
  locale: < cadena de caracteres >,  
  caseLevel: < boolean >,  
  caseFirst: < cadena de caracteres >,  
  strength: < entero >,  
  numericOrdering: < boolean >,  
  alternate: < cadena de caracteres >,  
  maxVariable: < cadena de caracteres >,  
  backwards: < boolean >  
} 

En este documento, solo el campo locale es obligatorio; contiene el idioma utilizado, anotado en el formato definido por la ICU (International Components for Unicode). Por lo que respecta al español, tenemos un valor de locale para cada país hispanoparlante empezando por España es_ES, obviamente (otros ejemplos serían: Argentina es_AR, Chile es_CL, Bolivia es_BO, México es_MX y así otros 19 más de un total de 24).

Veamos los demás campos del documento que describen la información de una intercalación:

  • strength (fuerza) representa el nivel de comparación que se realizará entre las cadenas de caracteres. Este nivel viene definido por la UCI: cuando el valor del campo strength es 1, se dice que el nivel de comparación es primario, es decir, que la comparación se realiza únicamente a partir de los caracteres, sin tener en cuenta acentuaciones ni mayúsculas o minúsculas. Cuando el valor del campo de strength es 2, el nivel de comparación se denomina secundario, es decir, además de la comparación primaria, ahora se tienen en cuenta los acentos. El nivel de comparación terciario es el predeterminado y, además de los criterios del nivel secundario, tendrá en cuenta las mayúsculas y minúsculas. Existen otros dos niveles, pero los tres...

Gestionar documentos

1. Insertar un documento

Ya hemos visto cómo insertar un documento al crear una base de datos. Solo se insertó un documento usando insertOne, pero obviamente es posible insertar varios simultáneamente colocándolos en una matriz usando insertMany. La sintaxis simplificada de insertOne es la siguiente:

db.collection.insertOne(<documento>) 

El insertMany es:

db.collection.insertMany(<tabla de documentos>) 

Volvamos a la tabla de documentos que creamos cuando vimos la estructura de un documento JSON:

[  
 { "apellido": "durand", "nombre": "robert"},  
 { "apellido": "dupont", "nombre": "france"}  
] 

Se trata de una matriz de objetos, porque los documentos son ante todo objetos. Ahora podemos conectarnos a test y ejecutar el siguiente comando:

Use test  
 
db.personas.insertMany([  
 { "apellido": "durand", "nombre": "robert"},  
 { "apellido": "dupont", "nombre": "france"}  
])  
 
{  
  acknowledged: true,  
  insertedIds: {  
    '0': ObjectId("65d5cd6e5a1b646dba13e33c"),  
    '1': ObjectId("65d5cd6e5a1b646dba13e33d")  
  }  
} 

¿Qué ocurre exactamente? Insertamos dos documentos en una colección llamada personas, que no existe; como nuestros documentos se insertan sin error, personas se crea cuando se ejecuta el comando de inserción.

El método insertMany gestiona las inserciones desordenadas: este tipo de inserción garantiza que, si se produce un error durante la inserción de varios documentos, la operación no se interrumpe y se insertan los documentos restantes. La inserción desordenada se realiza pasando un segundo documento que contiene el booleano false como parámetro a la clave ordered, como sigue:

db.personas.insertMany([  
 { "apellido": "durand", "nombre": "robert"},  
 { "apellido": "dupont", "nombre": "france"}  
], {"ordered": false}) 

De forma predefinida...

Las capped collections (colecciones limitadas)

Las colecciones limitadas (capped collections) son un tipo especial de colección, ya que tienen un tamaño fijo. Su comportamiento es el de un búfer circular: una vez alcanzada la capacidad máxima de la colección, cada documento insertado provocará automáticamente la eliminación del documento más antiguo de la colección.

Las capped collections conservan el orden de inserción, por lo que las consultas dirigidas a documentos de este tipo concreto de colección no tienen que depender de un índice que tenga en cuenta este orden, lo que tiene por efecto hacerlas más rápidas.

En particular, se utilizan para gestionar logs o bien cachés. El propio MongoDB utiliza este tipo de colección para su funcionamiento; el oplog − o registro de operaciones − es una capped collection que se utiliza para garantizar que las operaciones de replicación desde una máquina primaria a una secundaria se ejecuten sin problemas. Desde la versión 4 de MongoDB, el oplog tiene la posibilidad de crecer más allá de su capacidad máxima, convirtiéndolo en un caso muy especial de capped collections.

1. Crear una colección limitada

El comando para crear una cap collection es el mismo que para una colección normal, salvo que se debe especificar en las opciones de creación que está limitada y asignarle un tamaño en bytes. Si el tamaño introducido como parámetro es inferior o igual a 4 Kb, la colección se limita automáticamente a este valor. Además, cualquier tamaño que no sea múltiplo de 256 se redondea a un múltiplo de ese número. Creemos ahora una capped collection llamada coll_limitada y especifiquemos un tamaño de 5.000 bytes:

db.createCollection("coll_limitada", {"capped": true, "size": 5000}) 

El método isCapped, aplicable a una colección, utiliza un booleano para indicar si la colección en cuestión está o no limitada. En este caso, lo está y devolverá true:

db.coll_limitada.isCapped() 

Al consultar algunas de las propiedades de esta colección mediante el método db.coll_limitada.stats(), podemos ver que, efectivamente, el tamaño se ha redondeado...