En función de los requisitos de tu software, puedes priorizar la flexibilidad, la escalabilidad, el rendimiento o la velocidad. De ahí que los desarrolladores y las empresas se confunden a menudo al elegir una base de datos para sus necesidades. Si necesitas una base de datos que proporcione una gran flexibilidad y escalabilidad, y la agregación de datos para el análisis de los clientes, ¡MongoDB puede ser la más adecuada para ti!

En este artículo, hablaremos de la estructura de la base de datos MongoDB y de cómo crear, supervisar y gestionar tu base de datos. Empecemos.

¿Cómo Está Estructurada la Base de Datos de MongoDB?

MongoDB es una base de datos NoSQL sin esquema. Esto significa que no se especifica una estructura para las tablas/bases de datos como se hace con las bases de datos SQL.

¿Sabías que las bases de datos NoSQL son en realidad más rápidas que las bases de datos relacionales? Esto se debe a características como la indexación, la fragmentación y los canales de agregación. MongoDB también es conocida por su rapidez en la ejecución de consultas. Por eso lo prefieren empresas como Google, Toyota y Forbes.

A continuación, exploraremos algunas características clave de MongoDB.

Documentos

MongoDB tiene un modelo de datos de documentos que almacena los datos como documentos JSON. Los documentos se mapean de forma natural con los objetos del código de la aplicación, lo que hace más sencillo su uso para los desarrolladores.

En una tabla de base de datos relacional, debes añadir una columna para añadir un nuevo campo. Eso no ocurre con los campos de un documento JSON. Los campos de un documento JSON pueden variar de un documento a otro, por lo que no se añadirán a todos los registros de la base de datos.

Los documentos pueden almacenar estructuras como matrices que pueden anidarse para expresar relaciones jerárquicas. Además, MongoDB convierte los documentos en un tipo JSON binario (BSON). Esto garantiza un acceso más rápido y una mayor compatibilidad con varios tipos de datos como cadenas, enteros, números booleanos, ¡y mucho más!

Conjuntos de réplicas

Cuando creas una nueva base de datos en MongoDB, el sistema crea automáticamente al menos 2 copias más de tus datos. Estas copias se conocen como «conjuntos de réplicas«, y replican continuamente los datos entre ellas, garantizando una mayor disponibilidad de tus datos. También ofrecen protección contra el tiempo de inactividad durante un fallo del sistema o un mantenimiento planificado.

Colecciones

Una colección es un grupo de documentos asociados a una base de datos. Son similares a las tablas de las bases de datos relacionales.

Sin embargo, las colecciones son mucho más flexibles. Por un lado, no dependen de un esquema. En segundo lugar, ¡los documentos no tienen por qué ser del mismo tipo de datos!

Para ver una lista de las colecciones que pertenecen a una base de datos, utiliza el comando listCollections.

Tuberías de agregación

Puedes utilizar este marco para agrupar varios operadores y expresiones. Es flexible porque te permite procesar, transformar y analizar datos de cualquier estructura.

Por ello, MongoDB permite flujos de datos rápidos y características a través de 150 operadores y expresiones. También tiene varias etapas, como la etapa de Unión, que reúne de forma flexible los resultados de varias colecciones.

Índices

Puedes indexar cualquier campo de un documento de MongoDB para aumentar su eficacia y mejorar la velocidad de consulta. La indexación ahorra tiempo al escanear el índice para limitar los documentos inspeccionados. ¿No es esto mucho mejor que leer todos los documentos de la colección?

Puedes utilizar varias estrategias de indexación, incluidos los índices compuestos en varios campos. Por ejemplo, supongamos que tienes varios documentos que contienen el nombre y los apellidos del empleado en campos separados. Si quieres que se devuelvan el nombre y el apellido, puedes crear un índice que incluya tanto «Apellido» como «Nombre». Esto sería mucho mejor que tener un índice sobre «Apellidos» y otro sobre «Nombre».

Puedes aprovechar herramientas como el Asesor de Rendimiento para comprender mejor qué consulta podría beneficiarse de los índices.

Fragmentación

La fragmentación distribuye un único conjunto de datos en varias bases de datos. Ese conjunto de datos puede almacenarse en varias máquinas para aumentar la capacidad total de almacenamiento de un sistema. Esto se debe a que divide los conjuntos de datos más grandes en trozos más pequeños y los almacena en varios nodos de datos.

MongoDB fragmenta los datos a nivel de colección, distribuyendo los documentos de una colección entre los fragmentos de un clúster. Esto asegura la escalabilidad permitiendo que la arquitectura maneje las aplicaciones más grandes.

¿Cómo Crear una Base de Datos MongoDB?

Primero tendrás que instalar el paquete MongoDB adecuado para tu sistema operativo. Dirígete a la página ‘Descargar el Servidor de la Comunidad MongoDB‘. De las opciones disponibles, selecciona la última «versión», el formato del «paquete» como archivo zip, y la «plataforma» como tu sistema operativo y haz clic en «Descargar» como se muestra a continuación:

Esta imagen muestra las opciones disponibles: versión, plataforma y paquete al descargar MongoDB Community Server.
Proceso de descarga del servidor comunitario MongoDB. (Fuente de la imagen: MongoDB Community Server)

El proceso es bastante sencillo, así que tendrás MongoDB instalado en tu sistema en un abrir y cerrar de ojos.

Una vez que hayas realizado la instalación, abre tu símbolo del sistema y escribe mongod -version para verificarlo. Si no obtienes la siguiente salida y en su lugar ves una cadena de errores, es posible que tengas que volver a instalarlo:

Este es un fragmento de código para comprobar la versión de MongoDB después de la instalación.
Verificando la versión de MongoDB. (Fuente de la imagen: configserverfirewall)

Utilizar el Shell de MongoDB

Antes de empezar, asegúrate de que

  • Tu cliente tiene Seguridad de la Capa de Transporte y está en tu lista de IPs permitidas.
  • Tienes una cuenta de usuario y una contraseña en el clúster MongoDB deseado.
  • Has instalado MongoDB en tu dispositivo.

Paso 1: Acceder al shell de MongoDB

Inicia el servidor MongoDB siguiendo las instrucciones de cada sistema operativo. Para Windows, escribe el siguiente comando. Para otros SOs, consulta la documentación de MongoDB.

net start MongoDB

Esto debería dar la siguiente salida:

Ejecutando servidor MongoDB.
Ejecutando servidor MongoDB. (Fuente de la imagen: c-sharpcorner)

El comando anterior ha inicializado el servidor MongoDB. Para ejecutarlo, tendremos que escribir mongo en el símbolo del sistema.

Ejecutando el shell de MongoDB.
Ejecutando el shell de MongoDB. (Fuente de la imagen: bmc)

Aquí, en el shell de MongoDB, podemos ejecutar comandos para crear bases de datos, insertar datos, editar datos, emitir comandos administrativos y eliminar datos.

Paso 2: Crear tu base de datos

A diferencia de las bases de datos relacionales comunes, MongoDB no tiene un comando de creación de base de datos. En su lugar, hay una palabra clave llamada use que cambia a una base de datos especificada. Si la base de datos no existe, creará una nueva base de datos, si no, la enlazará con la base de datos existente.

Por ejemplo, para iniciar una base de datos llamada «empresa», escribe:

use Company
Este es un fragmento de código para crear una base de datos en MongoDB.
Crear una base de datos en MongoDB.

Puedes escribir db para confirmar la base de datos que acabas de crear en tu sistema. Si aparece la nueva base de datos que has creado, te has conectado a ella con éxito.

Si quieres comprobar las bases de datos existentes, escribe show dbs y te devolverá todas las bases de datos de tu sistema:

Este es un fragmento de código para ver las bases de datos existentes en el sistema.
Ver bases de datos en MongoDB.

Por defecto, al instalar MongoDB se crean las bases de datos admin, config y local.

¿Te has dado cuenta de que la base de datos que hemos creado no se muestra? Esto es porque aún no hemos guardado los valores en la base de datos. Hablaremos de la inserción en la sección de gestión de la base de datos.

Utilizar la interfaz de usuario de Atlas

También puedes empezar con el servicio de base de datos de MongoDB, Atlas. Aunque tengas que pagar para acceder a algunas características de Atlas, la mayoría de las funcionalidades de la base de datos están disponibles con el nivel gratuito. Las funciones del nivel gratuito son más que suficientes para crear una base de datos MongoDB.

Antes de empezar, asegúrate de que:

  1. Tu IP está en la lista permitida.
  2. Tienes una cuenta de usuario y una contraseña en el clúster de MongoDB que quieres utilizar.

Para crear una base de datos MongoDB con AtlasUI, abre una ventana del navegador e inicia sesión en https://cloud.mongodb.com. En la página de tu clúster, haz clic en Examinar colecciones. Si no hay bases de datos en el clúster, puedes crear tu base de datos haciendo clic en el botón Añadir mis propios datos.

El indicador te pedirá que proporciones un nombre de base de datos y de colección. Una vez que les hayas dado un nombre, haz clic en Crear y ¡ya está! Ahora puedes introducir nuevos documentos o conectarte a la base de datos mediante controladores.

Gestionar Tu base de datos MongoDB

En esta sección, repasaremos algunas formas ingeniosas de gestionar tu base de datos MongoDB de forma eficaz. Puedes hacerlo utilizando la brújula de MongoDB o mediante colecciones.

Utilizando colecciones

Mientras que las bases de datos relacionales poseen tablas bien definidas con tipos de datos y columnas específicas, NoSQL tiene colecciones en lugar de tablas. Estas colecciones no tienen ninguna estructura, y los documentos pueden variar: puedes tener diferentes tipos de datos y campos sin tener que coincidir con el formato de otro documento en la misma colección.

Para demostrarlo, vamos a crear una colección llamada «Empleado» y a añadirle un documento:

db.Employee.insert(
  {
   	"Employeename" : "Chris",
   	"EmployeeDepartment" : "Sales"
  }
)

Si la inserción tiene éxito, devolverá WriteResult({ "nInserted" : 1 }):

Este fragmento de código devuelve WriteResult({
Inserción exitosa en MongoDB.

Aquí, «db» se refiere a la base de datos conectada actualmente. «Empleado» es la colección recién creada en la base de datos de la empresa.

Aquí no hemos establecido una clave primaria porque MongoDB crea automáticamente un campo de clave primaria llamado «_id» y le asigna un valor por defecto.

Ejecuta el siguiente comando para comprobar la colección en formato JSON:

db.Employee.find().forEach(printjson)

Salida:

{
  "_id" : ObjectId("63151427a4dd187757d135b8"),
  "Employeename" : "Chris",
  "EmployeeDepartment" : "Sales"
}

Aunque el valor «_id» se asigna automáticamente, puedes cambiar el valor de la clave primaria por defecto. Esta vez, insertaremos otro documento en la base de datos «Empleado», con el valor «_id» como «1»:

db.Employee.insert(
  {  
   	"_id" : 1,
   	"EmployeeName" : "Ava",
   	"EmployeeDepartment" : "Public Relations"
  }
)

Al ejecutar el comando db.Employee.find().forEach(printjson) obtenemos la siguiente salida:

La salida muestra los documentos de la colección Empleados junto con su clave primaria
Documentos en la colección con su clave primaria.

En la salida anterior, el valor «_id» de «Ava» se establece en «1» en lugar de asignarle un valor automáticamente.

Ahora que hemos añadido con éxito valores a la base de datos, podemos comprobar si aparece en las bases de datos existentes en nuestro sistema mediante el siguiente comando:

show dbs
La salida muestra la colección de Empleados en las bases de datos existentes en nuestro sistema.
Visualizando la lista de bases de datos.

Y ¡voilá! ¡Has creado con éxito una base de datos en tu sistema!

Utilizar la brújula de MongoDB

Aunque podemos trabajar con servidores MongoDB desde la brújula de Mongo, a veces puede ser tedioso. Es posible que lo experimentes en un entorno de producción.

Sin embargo, existe una herramienta de brújula (llamada apropiadamente Compass) creada por MongoDB que puede facilitarlo. Tiene una interfaz gráfica de usuario mejor y funcionalidades añadidas como la visualización de datos, la elaboración de perfiles de rendimiento y el acceso CRUD (crear, leer, actualizar, eliminar) a los datos, las bases de datos y las colecciones.

Puedes descargar el IDE de Compass para tu sistema operativo e instalarlo con su sencillo proceso.

A continuación, abre la aplicación y crea una conexión con el servidor pegando la cadena de conexión. Si no la encuentras, puedes hacer clic en Rellenar los campos de conexión individualmente. Si no cambiaste el número de puerto al instalar MongoDB, sólo tienes que hacer clic en el botón de conexión, ¡y ya estás dentro! Si no, sólo tienes que introducir los valores que hayas establecido y hacer clic en Conectar.

Esta imagen muestra la ventana de Nueva Conexión, donde puedes elegir pegar la url de conexión.
Ventana de nueva conexión en MongoDB.. (Fuente de la imagen: mongodb)

A continuación, proporciona el nombre de host, el puerto y la autenticación en la ventana de nueva conexión.

En MongoDB Compass, puedes crear una base de datos y añadir su primera colección simultáneamente. Así es como se hace:

  1. Haz clic en Crear base de datos para abrir el aviso.
  2. Introduce el nombre de la base de datos y su primera colección.
  3. Haz clic en Crear base de datos.

Puedes insertar más documentos en tu base de datos haciendo clic en el nombre de tu base de datos, y luego haciendo clic en el nombre de la colección para ver la pestaña Documentos. A continuación, puedes hacer clic en el botón Añadir datos para insertar uno o varios documentos en tu colección.

Al añadir tus documentos, puedes introducirlos de uno en uno o como múltiples documentos en una matriz. Si añades varios documentos, asegúrate de que estos documentos separados por comas estén encerrados entre corchetes. Por ejemplo:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] },
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] },
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] },
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] },
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] },
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Por último, haz clic en Insertar para añadir los documentos a tu colección. Este es el aspecto que tendría el cuerpo de un documento:

{
  "StudentID" : 1
  "StudentName" : "JohnDoe"
}

Aquí, los nombres de los campos son «StudentID» y «StudentName». Los valores de los campos son «1» y «JohnDoe» respectivamente.

Comandos útiles

Puedes gestionar estas colecciones mediante los comandos de gestión de roles y de gestión de usuarios.

Comandos de gestión de usuarios

Los comandos de gestión de usuarios de MongoDB contienen comandos que pertenecen al usuario. Podemos crear, actualizar y eliminar los usuarios mediante estos comandos.

dropUser

Este comando elimina un único usuario de la base de datos especificada. A continuación se muestra la sintaxis:

db.dropUser(username, writeConcern)

Aquí, username es un campo obligatorio que especifica el nombre del usuario a eliminar de la base de datos. El campo opcional writeConcern contiene el nivel de preocupación de escritura para la operación de eliminación. El nivel de preocupación de escritura puede ser determinado por el campo opcional writeConcern.

Antes de dar de baja a un usuario que tiene el rol userAdminAnyDatabase, asegúrate de que hay al menos otro usuario con privilegios de administración de usuarios.

En este ejemplo, daremos de baja al usuario «user26» en la base de datos de prueba:

use test
db.dropUser("user26", {w: "majority", wtimeout: 4000})

Salida:

> db.dropUser("user26", {w: "majority", wtimeout: 4000});
true
createUser

Este comando crea un nuevo usuario para la base de datos especificada de la siguiente manera:

db.createUser(user, writeConcern)

Aquí, user es un campo obligatorio que contiene el documento con la información de autenticación y acceso del usuario a crear. El campo opcional writeConcern contiene el nivel de preocupación de escritura para la operación de creación. El nivel de preocupación por la escritura puede determinarse mediante el campo opcional writeConcern.

createUser devolverá un error de usuario duplicado si el usuario ya existe en la base de datos.

Puedes crear un nuevo usuario en la base de datos de prueba de la siguiente manera:

use test
db.createUser(
  {
    user: "user26",
    pwd: "myuser123",
    roles: [ "readWrite" ]  
  }
);

El resultado es el siguiente:

Successfully added user: { "user" : "user26", "roles" : [ "readWrite", "dbAdmin" ] }
grantRolesToUser

Puedes aprovechar este comando para conceder funciones adicionales a un usuario. Para utilizarlo, debes tener en cuenta la siguiente sintaxis:

db.runCommand(
  {
    grantRolesToUser: "<user>",
    roles: [ <roles> ],
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

Puedes especificar tanto los roles definidos por el usuario como los incorporados en los roles mencionados anteriormente. Si quieres especificar un rol que existe en la misma base de datos donde se ejecuta grantRolesToUser, puedes especificar el rol con un documento, como se menciona a continuación:

{ role: "<role>", db: "<database>" }

O bien, puedes especificar simplemente el rol con el nombre del rol. Por ejemplo:

"readWrite"

Si quieres especificar el rol que está presente en una base de datos diferente, tendrás que especificar el rol con un documento diferente.

Para conceder un rol en una base de datos, necesitas la acción grantRole en la base de datos especificada.

He aquí un ejemplo para que te hagas una idea clara. Tomemos, por ejemplo, un usuario productoUsuario00 en la base de datos de productos con los siguientes roles:

"roles" : [
  {
    "role" : "assetsWriter",
    "db" : "assets"
  }
]

La operación grantRolesToUser proporciona a «productoUsuario00» el rol readWrite en la base de datos de existencias y el rol de lectura en la base de datos de productos:

use products
db.runCommand({
  grantRolesToUser: "productUser00",
  roles: [
    { role: "readWrite", db: "stock"},
    "read"
  ],
  writeConcern: { w: "majority" , wtimeout: 2000 }
})

El usuario productoUsuario00 en la base de datos de productos posee ahora los siguientes roles:

"roles" : [
  {
    "role" : "assetsWriter",
    "db" : "assets"
  },
  {
    "role" : "readWrite",
    "db" : "stock"
  },
  {
    "role" : "read",
    "db" : "products"
  }
]
usersInfo

Puedes utilizar el comando usersInfo para devolver información sobre uno o varios usuarios. Esta es la sintaxis:

db.runCommand(
  {
    usersInfo: <various>,
    showCredentials: <Boolean>,
    showCustomData: <Boolean>,
    showPrivileges: <Boolean>,
    showAuthenticationRestrictions: <Boolean>,
    filter: <document>,
    comment: <any> 
  }
)
{ usersInfo: <various> }

En términos de acceso, los usuarios siempre pueden consultar su propia información. Para consultar la información de otro usuario, el usuario que ejecuta el comando debe tener privilegios que incluyan la acción viewUser en la base de datos del otro usuario.

Al ejecutar el comando userInfo, puedes obtener la siguiente información en función de las opciones especificadas:

{
  "users" : [
    {
      "_id" : "<db>.<username>",
      "userId" : <UUID>, // Starting in MongoDB 4.0.9
      "user" : "<username>",
      "db" : "<db>",
      "mechanisms" : [ ... ],  // Starting in MongoDB 4.0
      "customData" : <document>,
      "roles" : [ ... ],
      "credentials": { ... }, // only if showCredentials: true
      "inheritedRoles" : [ ... ],  // only if showPrivileges: true or showAuthenticationRestrictions: true
      "inheritedPrivileges" : [ ... ], // only if showPrivileges: true or showAuthenticationRestrictions: true
      "inheritedAuthenticationRestrictions" : [ ] // only if showPrivileges: true or showAuthenticationRestrictions: true
      "authenticationRestrictions" : [ ... ] // only if showAuthenticationRestrictions: true
    },
  ],
  "ok" : 1
} 

Ahora que ya tienes una idea general de lo que puedes conseguir con el comando usersInfo, la siguiente pregunta obvia que puede surgir es, ¿qué comandos serían útiles para consultar usuarios específicos y múltiples usuarios?

Aquí tienes dos prácticos ejemplos para ilustrar lo mismo:
Para ver los privilegios y la información de usuarios concretos, pero no las credenciales, de un usuario «Anthony» definido en la base de datos «oficina», ejecuta el siguiente comando:

db.runCommand(
  {
    usersInfo:  { user: "Anthony", db: "office" },
    showPrivileges: true
  }
)

Si quieres consultar un usuario de la base de datos actual, sólo puedes mencionar al usuario por su nombre. Por ejemplo, si estás en la base de datos «casa» y existe un usuario llamado «Timothy» en la base de datos «casa», puedes ejecutar el siguiente comando:

db.getSiblingDB("home").runCommand(
  {
    usersInfo:  "Timothy",
    showPrivileges: true
  }
)

A continuación, puedes utilizar una matriz si quieres consultar la información de varios usuarios. Puedes incluir los campos opcionales showCredentials y showPrivileges, o puedes optar por no incluirlos. Este es el aspecto que tendría el comando:

db.runCommand({
usersInfo: [ { user: "Anthony", db: "office" }, { user: "Timothy", db: "home" } ],
  showPrivileges: true
})
revokeRolesFromUser

Puedes aprovechar el comando revokeRolesFromUser para eliminar uno o varios roles de un usuario en la base de datos en la que están presentes los roles. El comando revokeRolesFromUser tiene la siguiente sintaxis:

db.runCommand(
  {
    revokeRolesFromUser: "<user>",
    roles: [
      { role: "<role>", db: "<database>" } | "<role>",
    ],
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

En la sintaxis mencionada anteriormente, puedes especificar tanto los roles definidos por el usuario como los incorporados en el campo roles. De forma similar al comando grantRolesToUser, puedes especificar el rol que quieres revocar en un documento o utilizar su nombre.

Para ejecutar con éxito el comando revokeRolesFromUser, necesitas tener la acción revokeRole en la base de datos especificada.

Aquí tienes un ejemplo para que quede claro. La entidad productUser00 de la base de datos de productos tenía los siguientes roles:

"roles" : [
  {
    "role" : "assetsWriter",
    "db" : "assets"
  },
  {
    "role" : "readWrite",
    "db" : "stock"
  },
  {
    "role" : "read",
    "db" : "products"
  }
]

El siguiente comando revokeRolesFromUser eliminará dos de los roles del usuario: el rol «leer» de products y el rol assetsWriter de la base de datos «activos»:

use products
db.runCommand( { revokeRolesFromUser: "productUser00",
  roles: [
    { role: "AssetsWriter", db: "assets" },
    "read"
  ],
  writeConcern: { w: "majority" }
} )

El usuario «productUser00» de la base de datos de productos ahora sólo tiene un rol restante:

"roles" : [
  {
    "role" : "readWrite",
    "db" : "stock"
  }
]

Comandos de gestión de roles

Los roles conceden a los usuarios el acceso a los recursos. Los administradores pueden utilizar varios roles integrados para controlar el acceso a un sistema MongoDB. Si los roles no cubren los privilegios deseados, puedes incluso ir más allá y crear nuevos roles en una base de datos concreta.

dropRole

Con el comando dropRole, puedes eliminar un rol definido por el usuario de la base de datos en la que ejecutas el comando. Para ejecutar este comando, utiliza la siguiente sintaxis:

db.runCommand(
  {
    dropRole: "<role>",
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

Para que se ejecute con éxito, debes tener la acción dropRole en la base de datos especificada. Las siguientes operaciones eliminarían el rol writeTags de la base de datos «productos»:

use products
db.runCommand(
  {
    dropRole: "writeTags",
    writeConcern: { w: "majority" }
  }
)
createRole

Puedes aprovechar el comando createRole para crear un rol y especificar sus privilegios. El rol se aplicará a la base de datos en la que decidas ejecutar el comando. El comando createRole devolverá un error de rol duplicado si el rol ya existe en la base de datos.

Para ejecutar este comando, sigue la sintaxis dada:

db.adminCommand(
  {
    createRole: "<new role>",
    privileges: [
      { resource: { <resource> }, actions: [ "<action>", ... ] },
    ],
    roles: [
      { role: "<role>", db: "<database>" } | "<role>",
    ],
    authenticationRestrictions: [
      {
        clientSource: ["<IP>" | "<CIDR range>", ...],
        serverAddress: ["<IP>" | "<CIDR range>", ...]
      },
    ],
    writeConcern: <write concern document>,
    comment: <any> 
  }
)

Los privilegios de un rol se aplicarían a la base de datos donde se creó el rol. El rol puede heredar privilegios de otros roles de su base de datos. Por ejemplo, un rol creado en la base de datos «admin» puede incluir privilegios que se apliquen a un clúster o a todas las bases de datos. También puede heredar privilegios de los roles presentes en otras bases de datos.

Para crear un rol en una base de datos, necesitas dos cosas:

  1. La acción grantRole en esa base de datos para mencionar los privilegios para el nuevo rol, así como para mencionar los roles de los que heredar.
  2. La acción createRole sobre ese recurso de la base de datos.

El siguiente comando createRole creará un rol clusterAdmin en la base de datos de usuarios:

db.adminCommand({ createRole: "clusterAdmin",
  privileges: [
    { resource: { cluster: true }, actions: [ "addShard" ] },
    { resource: { db: "config", collection: "" }, actions: [ "find", "remove" ] },
    { resource: { db: "users", collection: "usersCollection" }, actions: [ "update", "insert" ] },
    { resource: { db: "", collection: "" }, actions: [ "find" ] }
  ],
  roles: [
    { role: "read", db: "user" }
  ],
  writeConcern: { w: "majority" , wtimeout: 5000 }
})
grantRolesToRole

Con el comando grantRolesToRole, puedes conceder funciones a un rol definido por el usuario. El comando grantRolesToRole afectará a los roles de la base de datos donde se ejecute el comando.

Este comando grantRolesToRole tiene la siguiente sintaxis:

db.runCommand(
  {
    grantRolesToRole: "<role>",
    roles: [
     { role: "<role>", db: "<database>" },
    ],
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

Los privilegios de acceso son similares a los del comando grantRolesToUser – necesitas una acción grantRole en una base de datos para la correcta ejecución del comando.

En el siguiente ejemplo, puedes utilizar el comando grantRolesToRole para actualizar el rol productsReader en la base de datos «productos» para que herede los privilegios del rol productsWriter:

use products
db.runCommand(
  { 
    grantRolesToRole: "productsReader",
    roles: [
      "productsWriter"
    ],
    writeConcern: { w: "majority" , wtimeout: 5000 }
  }
)
revokePrivilegesFromRole

Puedes utilizar revokePrivilegesFromRole para eliminar los privilegios especificados del rol definido por el usuario en la base de datos donde se ejecuta el comando. Para una correcta ejecución, debes tener en cuenta la siguiente sintaxis:

db.runCommand(
  {
    revokePrivilegesFromRole: "<role>",
    privileges: [
      { resource: { <resource> }, actions: [ "<action>", ... ] },
    ],
    writeConcern: <write concern document>,
    comment: <any> 
  }
)

Para revocar un privilegio, el patrón «documento de recurso» debe coincidir con el campo «recurso» de ese privilegio. El campo «acciones» puede ser una coincidencia exacta o un subconjunto.

Por ejemplo, considera el rol manageRole en la base de datos de productos con los siguientes privilegios que especifican la base de datos «gestores» como recurso:

{
  "resource" : {
    "db" : "managers",
    "collection" : ""
  },
  "actions" : [
    "insert",
    "remove"
  ]
}

No puedes revocar las acciones «insertar» o «eliminar» de una sola colección en la base de datos de los gestores. Las siguientes operaciones no provocan ningún cambio en el rol:

use managers
db.runCommand(
  {
    revokePrivilegesFromRole: "manageRole",
    privileges: [
      {
        resource : {
          db : "managers",
          collection : "kiosks"
        },
        actions : [
          "insert",
          "remove"
        ]
      }
    ]
  }
)
db.runCommand(
  {
    revokePrivilegesFromRole: "manageRole",
    privileges:
      [
        {
          resource : {
          db : "managers",
          collection : "kiosks"
        },
        actions : [
          "insert"
        ]
      }
    ]
  }
)

Para revocar las acciones «insertar» y/o «eliminar» del rol manageRole, tienes que coincidir exactamente con el documento de recursos. Por ejemplo, la siguiente operación revoca sólo la acción «eliminar» del privilegio existente:

use managers
db.runCommand(
  {
    revokePrivilegesFromRole: "manageRole",
    privileges:
      [
        {
          resource : {
            db : "managers",
            collection : ""
        },
        actions : [ "remove" ]
      }
    ]
  }
)

La siguiente operación eliminará varios privilegios del rol «ejecutivo» en la base de datos de administradores:

use managers
db.runCommand(
  {
    revokePrivilegesFromRole: "executive",
    privileges: [
      {
        resource: { db: "managers", collection: "" },
        actions: [ "insert", "remove", "find" ]
      },
      {
        resource: { db: "managers", collection: "partners" },
        actions: [ "update" ]
      }
    ],
    writeConcern: { w: "majority" }
    }
)
rolesInfo

El comando rolesInfo devolverá la información sobre privilegios y herencia de los roles especificados, incluidos los roles incorporados y los definidos por el usuario. También puedes aprovechar el comando rolesInfo para recuperar todos los roles asignados a una base de datos.

Para una correcta ejecución, sigue esta sintaxis:

db.runCommand(
  {
    rolesInfo: { role: <name>, db: <db> },
    showPrivileges: <Boolean>,
    showBuiltinRoles: <Boolean>,
    comment: <any> 
  }
)

Para devolver la información de un rol de la base de datos actual, puedes especificar su nombre de la siguiente manera:

{ rolesInfo: "<rolename>" }

Para devolver información de un rol de otra base de datos, puedes mencionar el rol con un documento que mencione el rol y la base de datos:

{ rolesInfo: { role: "<rolename>", db: "<database>" } }

Por ejemplo, el siguiente comando devuelve la información de la herencia del rol del ejecutivo definido en la base de datos de los gestores:

db.runCommand(
   {
      rolesInfo: { role: "executive", db: "managers" }
   }
)

El siguiente comando devolverá la información de la herencia de roles: accountManager en la base de datos en la que se ejecuta el comando:

db.runCommand(
   {
      rolesInfo: "accountManager"
   }
)

El siguiente comando devolverá tanto los privilegios como la herencia de roles para el rol «ejecutivo» tal y como está definido en la base de datos de los gestores:

db.runCommand(
   {
     rolesInfo: { role: "executive", db: "managers" },
     showPrivileges: true
   }
)

Para mencionar varios roles, puedes utilizar una matriz. También puedes mencionar cada rol en la matriz como una cadena o un documento.

Debes utilizar una cadena sólo si el rol existe en la base de datos en la que se ejecuta el comando:

{
  rolesInfo: [
    "<rolename>",
    { role: "<rolename>", db: "<database>" },
  ]
}

Por ejemplo, el siguiente comando devolverá información de tres roles en tres bases de datos diferentes:

db.runCommand(
   {
    rolesInfo: [
      { role: "executive", db: "managers" },
      { role: "accounts", db: "departments" },
      { role: "administrator", db: "products" }
    ]
  }
)

Puedes obtener tanto los privilegios como la herencia de los roles de la siguiente manera:

db.runCommand(
  {
    rolesInfo: [
      { role: "executive", db: "managers" },
      { role: "accounts", db: "departments" },
      { role: "administrator", db: "products" }
    ],
    showPrivileges: true
  }
)

Incrustar Documentos de MongoDB para Mejorar el Rendimiento

Las bases de datos de documentos como MongoDB te permiten definir tu esquema según tus necesidades. Para crear esquemas óptimos en MongoDB, puedes agrupar los documentos. Así, en lugar de ajustar tu aplicación a un modelo de datos, puedes construir un modelo de datos que se ajuste a tu caso de uso.

Los documentos agrupados te permiten almacenar datos relacionados a los que se accede conjuntamente. Al diseñar esquemas para MongoDB, se recomienda incrustar documentos por defecto. Utiliza las uniones y referencias del lado de la base de datos o de la aplicación sólo cuando merezcan la pena.

Asegúrate de que la carga de trabajo pueda recuperar un documento con la frecuencia necesaria. Al mismo tiempo, el documento debe tener todos los datos que necesita. Esto es fundamental para que tu aplicación tenga un rendimiento excepcional.

A continuación, encontrarás algunos patrones diferentes para incrustar documentos:

Patrón de documento incrustado

Puedes utilizarlo para incrustar incluso subestructuras complicadas en los documentos con los que se utilizan. Incrustar datos conectados en un solo documento puede disminuir el número de operaciones de lectura necesarias para obtener los datos. En general, debes estructurar tu esquema de forma que tu aplicación reciba toda la información necesaria en una sola operación de lectura. Por lo tanto, la regla que hay que tener en cuenta aquí es que lo que se usa junto debe almacenarse junto.

Patrón de subconjunto incrustado

El patrón de subconjunto incrustado es un caso híbrido. Lo utilizarías para una colección separada de una larga lista de elementos relacionados, donde puedes mantener algunos de esos elementos a mano para su visualización.

Aquí tienes un ejemplo que enumera críticas de películas:

> db.movie.findOne()
{   
  _id: 321475,   
  title: "The Dark Knight"
}  
> db.review.find({movie_id: 321475})
{   
  _id: 264579,   
  movie_id: 321475,   
  stars: 4   
  text: "Amazing"   
}
{   
  _id: 375684,   
  movie_id: 321475,   
  stars:5,   
  text: "Mindblowing"
}

Ahora, imagina mil críticas similares, pero sólo piensas mostrar las dos más recientes cuando proyectes una película. En este caso, tiene sentido almacenar ese subconjunto como una lista dentro del documento de la película:

> db.movie.findOne({_id: 321475})   
{   
  _id: 321475,   
  title: "The Dark Knight",   
  recent_reviews: [   
    {_id: 264579, stars: 4, text: "Amazing"},   
    {_id: 375684, stars: 5, text: "Mindblowing"}   
  ]   
}

En pocas palabras, si accedes habitualmente a un subconjunto de elementos relacionados, asegúrate de incrustarlo.

Acceso independiente

Puede que quieras almacenar los subdocumentos en su colección para separarlos de su colección principal.

Por ejemplo, toma la línea de productos de una empresa. Si la empresa vende un pequeño conjunto de productos, quizá quieras almacenarlos dentro del documento de la empresa. Pero si quieres reutilizarlos entre empresas o acceder a ellos directamente por su unidad de mantenimiento de stock (SKU), también querrás almacenarlos en su colección.

Si manipulas o accedes a una entidad de forma independiente, haz una colección para almacenarla por separado, para una mejor práctica.

Listas no limitadas

Almacenar listas cortas de información relacionada en su documento tiene un inconveniente. Si tu lista sigue creciendo sin límites, no deberías ponerla en un solo documento. Esto se debe a que no podrías mantenerla durante mucho tiempo.

Hay dos razones para ello. En primer lugar, MongoDB tiene un límite en el tamaño de un solo documento. En segundo lugar, si accedes al documento con demasiada frecuencia, verás resultados negativos por el uso incontrolado de la memoria.

En pocas palabras, si una lista empieza a crecer de forma ilimitada, haz una colección para almacenarla por separado.

Patrón de referencia extendido

El patrón de referencia extendido es como el patrón de subconjuntos. También optimiza la información a la que accedes regularmente para almacenarla en el documento.

Aquí, en lugar de una lista, se aprovecha cuando un documento hace referencia a otro que está presente en la misma colección. Al mismo tiempo, también almacena algunos campos de ese otro documento para poder acceder a ellos.

Por ejemplo:

> db.movie.findOne({_id: 245434})
{   
  _id: 245434,   
  title: "Mission Impossible 4 - Ghost Protocol",   
  studio_id: 924935,   
  studio_name: "Paramount Pictures"   
}

Como puedes ver, «el studio_id» se almacena para que puedas buscar más información sobre el estudio que creó la película. Pero el nombre del estudio también se copia en este documento para simplificar.

Para incrustar la información de los documentos modificados regularmente, recuerda actualizar los documentos en los que has copiado esa información cuando se modifique. En otras palabras, si accedes habitualmente a algunos campos de un documento referenciado, incrústalos.

Cómo Monitorizar MongoDB

Puedes utilizar herramientas de monitorización como Kinsta APM para depurar las llamadas largas a la API, las consultas lentas a la base de datos, las peticiones largas a la URL externa, por nombrar algunas. Incluso puedes aprovechar los comandos para mejorar el rendimiento de la base de datos. También puedes utilizarlas para inspeccionar la salud de tus instancias de base de datos.

¿Por qué deberías monitorizar las bases de datos MongoDB?

Un aspecto clave de la planificación de la administración de la base de datos es la supervisión del rendimiento y la salud de tu clúster. MongoDB Atlas se encarga de la mayoría de los esfuerzos de administración gracias a sus capacidades de tolerancia a fallos/escalado.

A pesar de ello, los usuarios deben saber cómo hacer un seguimiento de los clusters. También deben saber cómo escalar o ajustar lo que necesiten antes de llegar a una crisis.

Al monitorizar las bases de datos MongoDB, puedes:

  • Observar la utilización de los recursos.
  • Comprender la capacidad actual de tu base de datos.
  • Reaccionar y detectar problemas en tiempo real para mejorar tu pila de aplicaciones.
  • Observar la presencia de problemas de rendimiento y comportamientos anómalos.
  • Alinearse con tus requisitos de gobernanza/protección de datos y acuerdos de nivel de servicio (SLA).

Métricas clave a monitorizar

Al monitorizar MongoDB, hay cuatro aspectos clave que debes tener en cuenta:

Métricas de hardware de MongoDB

Estas son las principales métricas para monitorizar el hardware:

CPU de proceso normalizada

Se define como el porcentaje de tiempo dedicado por la CPU al software de aplicación que mantiene el proceso de MongoDB.

Puedes escalar esto a un rango de 0-100% dividiéndolo por el número de núcleos de la CPU. Incluye la CPU aprovechada por módulos como el kernel y el usuario.

Una CPU del kernel alta podría mostrar el agotamiento de la CPU a través de las operaciones del sistema operativo. Pero el usuario vinculado a las operaciones de MongoDB podría ser la causa principal del agotamiento de la CPU.

CPU normalizada del sistema

Es el porcentaje de tiempo que la CPU dedica a las llamadas del sistema para atender a este proceso de MongoDB. Puedes escalarlo a un rango de 0-100% dividiéndolo por el número de núcleos de la CPU. También cubre la CPU utilizada por módulos como iowait, user, kernel, steal, etc.

Una CPU de usuario o un kernel alto podrían mostrar un agotamiento de la CPU por las operaciones de MongoDB (software). Un iowait alto podría estar relacionado con el agotamiento del almacenamiento que provoca el agotamiento de la CPU.

IOPS de disco

Las IOPS de disco son el promedio de operaciones IO consumidas por segundo en la partición de disco de MongoDB.

Latencia del disco

Es la latencia de lectura y escritura en disco de la partición de MongoDB en milisegundos. Los valores altos (>500ms) muestran que la capa de almacenamiento puede afectar al rendimiento de MongoDB.

Memoria del sistema

Utiliza la memoria del sistema para describir los bytes de memoria física utilizados frente al espacio libre disponible.

La métrica disponible se aproxima al número de bytes de memoria del sistema disponibles. Puedes utilizarla para ejecutar nuevas aplicaciones, sin hacer swapping.

Espacio libre en el disco

Se define como el total de bytes de espacio libre en la partición de disco de MongoDB. El Atlas de MongoDB proporciona capacidades de autoescalado basadas en esta métrica.

Uso de swap

Puedes aprovechar un gráfico de uso de swap para describir cuánta memoria se está colocando en el dispositivo de swap. Una métrica de alto uso en este gráfico muestra que la swap está siendo utilizada. Esto muestra que la memoria está infraaprovisionada para la carga de trabajo actual.

Métricas de Conexión y Operación del Cluster MongoDB

Estas son las principales métricas de Operación y Conexión:

Tiempos de ejecución de las operaciones

El tiempo medio de las operaciones (operaciones de escritura y lectura) realizadas durante el periodo de muestra seleccionado.

Contadores de operaciones

Es la tasa media de operaciones ejecutadas por segundo a lo largo del periodo de muestra seleccionado. El gráfico/métrico Opcounters muestra el desglose de operaciones por tipos de operación y velocidad para la instancia.

Conexiones

Esta métrica se refiere al número de conexiones abiertas a la instancia. Los picos o números elevados podrían indicar una estrategia de conexión subóptima, ya sea del lado del servidor que no responde o del lado del cliente.

Orientación de la consulta y ejecutores de la consulta

Es la tasa media por segundo durante el periodo de muestra seleccionado de documentos escaneados. En el caso de los ejecutores de consulta, se trata de la evaluación del plan de consulta y de las consultas. La orientación de la consulta muestra la relación entre el número de documentos escaneados y el número de documentos devueltos.

Un ratio de número elevado señala operaciones subóptimas. Estas operaciones escanean muchos documentos para devolver una parte menor.

Escanear y ordenar

Describe la tasa media por segundo a lo largo del periodo de muestra de consultas elegido. Devuelve resultados ordenados que no pueden ejecutar la operación de ordenación mediante un índice.

Colas

Las colas pueden describir el número de operaciones que esperan un bloqueo, ya sea de escritura o de lectura. Unas colas elevadas podrían representar la existencia de un diseño de esquema poco óptimo. También podría indicar la existencia de rutas de escritura conflictivas, lo que supone una alta competencia por los recursos de la base de datos.

Métricas de replicación de MongoDB

Estas son las principales métricas para la monitorización de la replicación:

Ventana Oplog de Replicación

Esta métrica indica el número aproximado de horas disponibles en el oplog de replicación del primario. Si un secundario se retrasa más de esta cantidad, no puede seguir el ritmo y necesitará una resincronización completa.

Retraso en la replicación

El retraso en la replicación se define como el número aproximado de segundos que un nodo secundario va por detrás del primario en las operaciones de escritura. Un retraso de replicación elevado indicaría que el secundario tiene dificultades para replicarse. Podría afectar a la latencia de tu operación, dada la preocupación por la lectura/escritura de las conexiones.

Espacio libre de replicación

Esta métrica se refiere a la diferencia entre la ventana de oplog de la replicación primaria y el retardo de replicación del secundario. Si este valor llega a cero, puede provocar que el secundario entre en modo RECUPERACIÓN.

Opcounters -repl

Opcounters -repl se define como la tasa media de operaciones de replicación ejecutadas por segundo para el periodo de muestra elegido. Con la métrica opcounters -graph/, puedes echar un vistazo a la velocidad de las operaciones y al desglose de los tipos de operaciones para la instancia especificada.

Oplog GB/Hora

Se define como la tasa media de gigabytes de oplog que el primario genera por hora. Los altos volúmenes inesperados de oplog podrían indicar una carga de trabajo de escritura muy insuficiente o un problema de diseño del esquema.

Herramientas de monitorización del rendimiento de MongoDB

MongoDB tiene herramientas de interfaz de usuario integradas en Cloud Manager, Atlas y Ops Manager para el seguimiento del rendimiento. También proporciona algunos comandos y herramientas independientes para observar datos más crudos. Hablaremos de algunas herramientas que puedes ejecutar desde un host que tenga acceso y roles adecuados para comprobar tu entorno:

mongotop

Puedes aprovechar este comando para hacer un seguimiento de la cantidad de tiempo que una instancia de MongoDB pasa escribiendo y leyendo datos por colección. Utiliza la siguiente sintaxis:

mongotop <options> <connection-string> <polling-interval in seconds>

rs.status()

Este comando devuelve el estado del conjunto de réplicas. Se ejecuta desde el punto de vista del miembro donde se ejecuta el método.

mongostat

Puedes utilizar el comando mongostat para obtener una visión rápida del estado de tu instancia del servidor MongoDB. Para obtener un resultado óptimo, puedes utilizarlo para vigilar una sola instancia para un evento específico, ya que ofrece una vista en tiempo real.

Aprovecha este comando para supervisar las estadísticas básicas del servidor, como las colas de bloqueo, el desglose de operaciones, las estadísticas de memoria de MongoDB y las conexiones/red:

mongostat <options> <connection-string> <polling interval in seconds>

dbStats

Este comando devuelve las estadísticas de almacenamiento de una base de datos concreta, como el número de índices y su tamaño, los datos totales de la colección frente al tamaño de almacenamiento, y las estadísticas relacionadas con la colección (número de colecciones y documentos).

db.serverStatus()

Puedes aprovechar el comando db.serverStatus() para tener una visión general del estado de la base de datos. Te proporciona un documento que representa los contadores de métrica de la instancia actual. Ejecuta este comando a intervalos regulares para cotejar las estadísticas de la instancia.

collStats

El comando collStats recoge estadísticas similares a las que ofrece dbStats a nivel de colección. Su salida consiste en un recuento de los objetos de la colección, la cantidad de espacio en disco consumido por la colección, el tamaño de la colección y la información relativa a sus índices para una colección determinada.

Puedes utilizar todos estos comandos para ofrecer informes y monitorización en tiempo real del servidor de la base de datos que te permitan controlar el rendimiento y los errores de la base de datos y te ayuden a tomar decisiones informadas para perfeccionar una base de datos.

Cómo Eliminar una Base de Datos MongoDB

Para eliminar una base de datos que hayas creado en MongoDB, tienes que conectarte a ella mediante la palabra clave use.

Digamos que has creado una base de datos llamada «Ingenieros». Para conectarte a la base de datos, utilizarás el siguiente comando:

use Engineers

A continuación, escribe db.dropDatabase() para deshacerte de esta base de datos. Tras la ejecución, este es el resultado que puedes esperar:

{ "dropped"  :  "Engineers", "ok" : 1 }

Puedes ejecutar el comando showdbs para verificar si la base de datos sigue existiendo.

Resumen

Para exprimir hasta la última gota de valor de MongoDB, debes tener una sólida comprensión de los fundamentos. Por lo tanto, es fundamental conocer las bases de datos MongoDB como la palma de tu mano. Para ello, primero debes familiarizarte con los métodos para crear una base de datos.

En este artículo, arrojamos luz sobre los diferentes métodos que puedes utilizar para crear una base de datos en MongoDB, seguido de una descripción detallada de algunos ingeniosos comandos de MongoDB para mantenerte al tanto de tus bases de datos. Por último, completamos la discusión hablando de cómo puedes aprovechar los documentos incrustados y las herramientas de monitorización del rendimiento en MongoDB para garantizar que tu flujo de trabajo funcione con la máxima eficiencia.

¿Cuál es tu opinión sobre estos comandos de MongoDB? ¿Hemos omitido algún aspecto o método que te hubiera gustado ver aquí? ¡Háznoslo saber en los comentarios!

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.