Cómo aplicar reglas de validación de esquema en una colección

Breve introducción

MongoDB es una base de datos orientada a documentos muy popular, gratuita y de código abierto. Es una base de datos NoSQL y se basa en documentos tipo JSON. Las bases de datos basadas en documentos no tienen esquema o proporcionan un cierto nivel de flexibilidad al definir los esquemas mediante reglas de validación de los mismos.

Para aquellos que vienen del mundo RDBMS, donde la estructura de una tabla se caracteriza por columnas con propiedades estrictamente definidas (tipo, tamaño, etc.), la capacidad de definir esquemas podría resultar una opción bastante útil.

En general, podemos pensar que un objeto de base de datos MongoDB es similar a un esquema RDBMS que contiene tablas, vistas y otros objetos RDBMS. Respectivamente, una colección MongoDB es análoga a una tabla, y un documento MongoDB puede considerarse como una fila de la tabla.

Una base de datos MongoDB puede agrupar colecciones, una colección contiene documentos, y un documento está formado por varios objetos de pares clave-valor, e incluso por otros documentos.

El objetivo de este post es demostrar cómo podemos aplicar algunas reglas de validación de esquemas en una colección. Para ello, es necesario crear una base de datos MongoDB de ejemplo con una colección MongoDB.

Prerrequisitos y Supuestos y Supuestos Supuestos

Aquí puede obtener una visión general.

Se supone que tienes una instancia de MongoDB disponible y accesible. Si no la tienes, puedes conseguirlo fácilmente utilizando también Docker y la imagen oficial de Docker de MongoDB para ejecutar un contenedor de MongoDB. Lee más en https://www.mongodb.com/compatibility/docker.

Para mayor comodidad, también vamos a utilizar el MongoDB Compass que es la GUI oficial de MongoDB.

Ejecutar un contenedor Docker de MongoDB

Puedes crear y ejecutar un contenedor Docker llamado ‘mongodb’ ejecutando el siguiente comando:

docker run --name mongodb -p 27017:27017 -d mongo

Después de crear el contenedor, puede detenerlo e iniciarlo utilizando los siguientes comandos, respectivamente:

docker stop mongodb
docker start mongodb

Además, siempre puedes comprobar los contenedores en ejecución, a través de lo siguiente:

docker ps

Obtener la Gui MongoDB Compass y definir una base de datos y una colección

Puede descargar la GUI Compass en el siguiente enlace:

https://www.mongodb.com/try/download/compass

Después de instalarlo, ejecútelo. Asegúrate de que el contenedor mongodb está en marcha y crea una nueva conexión utilizando una cadena de conexión, que para nuestro caso puede ser la siguiente

mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&directConnection=true&ssl=false

Entonces, después de que te hayas conectado con éxito a una instancia docker de MongoDB, puedes crear una nueva base de datos y una nueva colección. Nómbralas ‘ticket-management’ y ‘users’, respectivamente.

La colección ‘users’ almacenará los documentos de los usuarios y los documentos deberán ser validados por nuestras reglas de validación.

Definir las propiedades de un documento MongoDB

Como hemos dicho antes, un documento de MongoDB es un conjunto ordenado de pares clave-valor. Una diferencia clave con el RDBMS es que un documento de MongoDB puede almacenar documentos de cualquier tamaño de pares clave-valor, así como documentos anidados.


Sin embargo, en nuestro caso, queremos imponer que la colección “users” contenga documentos de estrictamente las mismas propiedades (keys). Esto es análogo a los campos (columns) de una tabla en un RDBMS. Así, por ejemplo, queremos que cada documento tenga exactamente las mismas propiedades/campos.

El _id de mongo

Antes de identificar los campos de nuestra colección ‘users’, cabe mencionar que MongoDB genera automáticamente una propiedad/campo especial _id cada vez que se inserta un nuevo documento en una colección.
El _id es un tipo de dato especial para MongoDB. En realidad es un objeto MongoDB (ObjectID) de tipo BSON con un tamaño de 12 bytes. El _id de 12 bytes consiste en lo siguiente:

  • 4 bytes que representan los segundos de Unix epoch
  • 3 bytes específicos del host – un identificador de máquina
  • 2 bytes del id del proceso, y
  • 3 bytes que representan un contador, empezando por un valor aleatorio.

Incluso el hecho de que un _id autogenerado no sea realmente un UUID estándar. Los campos _id pueden considerarse únicos. Están ordenados, y pueden ser utilizados como la ‘key primaria’ de nuestra colección.


Después de esto, esta es la lista de ejemplo de los campos para la colección ‘users’:
_id

_id
username,
password,
email,
registrationdate,
confirmed,
cancelled,
typeid,
countryid

El objetivo es asegurar (bueno, todo lo que podamos) que todos los documentos que se pretendan insertar en la colección “user” estén formados por esos campos.

Reglas de validación del esquema de MongoDB

Para conseguir que todos los documentos cumplan con los campos anteriores, utilizaremos un esquema específico de MongoDB. Se puede pensar que un esquema MongoDB no es más que un conjunto de reglas para las propiedades (Keys) y valores de los documentos. Dichas reglas funcionan en función de cada colección. Las reglas deben seguirse (=validated) durante la inserción o actualización de cada documento en la colección específica.


Este conjunto de reglas debe definirse mediante un archivo JSON de acuerdo con los estándares BSON.


No vamos a entrar en más detalles aquí, pero puedes leer más sobre el esquema de MongoDB y su funcionamiento utilizando la documentación oficial. Por ejemplo, puedes seguir los siguientes enlaces:

Después de la breve introducción dada anteriormente, ahora es el momento de definir nuestro esquema de validación de MongoDB. El resumen de lo que realmente queremos definir se da a continuación:

  • Los campos: nombre de usuario, correo electrónico y contraseña deben estar presentes en cada documento (son obligatorios).
  • Los campos: nombre de usuario, correo electrónico y contraseña deben ser de tipo string, y la longitud de sus cadenas debe estar entre los límites mínimo y máximo.
  • El campo de correo electrónico debe cumplir con un patrón de expresión regular específico.
  • El campo: fecha de registro (registrationdate) debe ser del tipo fecha.
  • Los campos: confirmado y cancelado deben ser de tipo booleano (Booleano: verdadero o falso).
  • Los campos typeid y countryid deben ser de tipo int (entero), y sus valores deben estar entre un número mínimo y uno máximo.

Definimos nuestras reglas a través de varios métodos a través de mongo shell CLI o mongosh CLI, pero dado que ya hemos creado nuestra colección de “use” en Compass, usar la GUI de Compass parece ser la forma conveniente.

Entonces, selecciona la colección ‘users’, haz clic en la pestaña Validation y pon tu esquema JSON (deja las opciones Validation Action y Validation Level en ERROR y STRICT, respectivamente). A continuación se muestra nuestro ejemplo de reglas de validación que utilizaremos:

mongodb (compass) collection validation schema

esquema de validación de la colección mongodb (brújula)

Comprobar las reglas de validación a través de Mongosh y Mongo Shell CLIs

Después de haber guardado nuestras reglas de validación en Compass, podemos utilizar el mongosh para tener una idea de cómo son. Compass nos proporciona una versión incrustada del mongosh CLI.

Por defecto, el mongosh está conectado a la base de datos ‘test’, como puedes ver arriba. Por lo tanto, cambie a la base de datos de gestión de tickets y navegue hasta las reglas de validación utilizando la función db.getCollectionInfos():

Parece que no podemos navegar, ver y comprobar las “propiedades” de los objetos utilizando el mongosh.

Sin embargo, podemos saltar al shell del contenedor:

docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS       PORTS                      NAMES
11b9a599c13e   mongodb   "docker-entrypoint.s…"   3 months ago   Up 4 hours   0.0.0.0:27017->27017/tcp   mongodb
. . .
docker exec -it mongodb bash
root@11b9a599c13e:/#

Y ejecuta el mongosh desde dentro usando estos comandos:

root@11b9a599c13e:/# 
root@11b9a599c13e:/# mongosh
Current Mongosh Log ID:    6229dc064130345cc3d542bf
Connecting to:        mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000
Using MongoDB:        5.0.5
Using Mongosh:        1.1.6
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
To help improve our products, anonymous usage data is collected and sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-policy).
You can opt-out by running the disableTelemetry() command.
------
   The server generated these startup warnings when booting:
   2022-03-10T05:41:44.202+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2022-03-10T05:41:45.856+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
------
Warning: Found ~/.mongorc.js, but not ~/.mongoshrc.js. ~/.mongorc.js will not be loaded.
  You may want to copy or rename ~/.mongorc.js to ~/.mongoshrc.js.
test>

A continuación, podemos pasar a la base de datos de gestión de tickets y ejecutar la función db.collectionInfos() para obtener la información de las reglas de validación de la colección ‘users’, como se puede ver a continuación:

Esta vez nuestras reglas de validación se presentan claramente.


Alternativamente, podemos ejecutar sólo el CLI de mongo (no el mongosh), que se muestra a continuación:

root@11b9a599c13e:/# mongo
MongoDB shell version v5.0.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("bb023c59-6160-461d-b022-4d88658fb890") }
MongoDB server version: 5.0.5
================
Warning: the "mongo" shell has been superseded by "mongosh",
which delivers improved usability and compatibility.The "mongo" shell has been deprecated and will be removed in
an upcoming release.
For installation instructions, see
https://docs.mongodb.com/mongodb-shell/install/
================
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
    https://docs.mongodb.com/
Questions? Try the MongoDB Developer Community Forums
    https://community.mongodb.com
---
The server generated these startup warnings when booting: 
        2022-03-10T05:41:44.202+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
        2022-03-10T05:41:45.856+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
---
---
        Enable MongoDB's free cloud-based monitoring service, which will then receive and display
        metrics about your deployment (disk utilization, CPU, operation statistics, etc).
        The monitoring data will be available on a MongoDB website with a unique URL accessible to you
        and anyone you share the URL with. MongoDB may use this information to make product
        improvements and to suggest MongoDB products and deployment options to you.
        To enable free monitoring, run the following command: db.enableFreeMonitoring()
        To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
>

Ten en cuenta que el shell mongo está depreciado, y ha sido sustituido por el mongosh.
También podemos pasar a la base de datos de gestión de tickets y ejecutar db.collectionInfos() para obtener dicha información para la colección ‘users’:

Como puedes ver arriba, el resultado es prácticamente el mismo.


Pruebe nuestras reglas de validación

Después de haber definido nuestras reglas de validación, podemos utilizar cualquiera de las herramientas disponibles (Compass GUI, mongosh CLI, mongo CLI) y probar si funcionan correctamente. Para ello, podemos intentar insertar algunos documentos que no cumplan los requisitos de las reglas de validación y confirmar su fallo. A continuación, hay algunos ejemplos de este tipo que también pueden ser utilizados por los tuyos.

Usando mongosh

Intentemos insertar un documento vacío:

Ahora intentemos de nuevo con un documento con un correo electrónico no válido:

Puede seguir intentando insertar documentos con valores no válidos, por ejemplo, utilizando un valor del campo typeid – el valor 0, por ejemplo, cuando debería ser como mínimo:

Usando Compass

Del mismo modo, al intentar insertar documentos que no cumplen con nuestras reglas de validación, seguirá obteniendo errores de fallo, como el siguiente:

Advertencias


El uso de las reglas de validación de MongoDB es bastante útil y nos ahorra muchos dolores de cabeza. Sin embargo, no es la panacea. Como ejemplo de inconveniente, podemos mencionar la incapacidad de definir la unicidad con los campos, por ejemplo, no podemos evitar la inserción (o actualización) de un documento con un valor de nombre de usuario que ya existe en otro documento.
Otro ejemplo es que tampoco podemos impedir la inserción de documentos que no tengan todos los campos (aparte de los obligatorios). Y así sucesivamente.
Sin embargo, como sugiere MongoDB, estos retos pueden ser resueltos en nuestra lógica de negocio en el middleware, pero esto es objeto de otro post. Así que, ¡estén atentos!
Eso es todo.
Gracias por leer, y ¡feliz codificación!