MongoDB desde cero: documentos, colecciones y el cambio del modelo NoSQL

DUGLAS MORENODUGLAS MORENO 👁 1

MongoDB desde cero: documentos, colecciones y el cambio del modelo NoSQL

Introducción

Si estás dando tus primeros pasos en el mundo del desarrollo de software, seguramente ya habrás escuchado hablar de bases de datos y, muy probablemente, de SQL. Las bases de datos relacionales (como MySQL, PostgreSQL o SQLite) son las que más se estudian en las aulas y las que la mayoría usamos en proyectos pequeños. Sin embargo, en los últimos años ha surgido un modelo alternativo: las bases de datos NoSQL.

MongoDB es uno de los representantes más populares de este enfoque. A diferencia de una tabla con filas y columnas, MongoDB guarda la información en documentos similares a JSON, organizados en colecciones. Esta estructura permite modelar datos de forma mucho más flexible, una característica que resulta esencial cuando trabajás con requisitos cambiantes, datos no estructurados o aplicaciones que necesitan escalar horizontalmente.

En este artículo, vamos a explicar MongoDB desde cero. Veremos qué son un documento y una colección, cómo crearlos, realizar operaciones CRUD básicas y, lo más importante, entender por qué el modelo NoSQL representa un cambio en la forma de pensar los datos en comparación con las bases de datos relacionales. Todo esto acompañado de ejemplos prácticos con la salida esperada, para que podás seguirlos sin perderte.

El contenido está orientado a desarrolladores back‑end, estudiantes de ingeniería o ciencia de datos, y a cualquier persona que quiera comprender los fundamentos de MongoDB antes de adentrarse en casos de uso más complejos.


¿Qué es MongoDB?

MongoDB es un almacén de datos NoSQL orientado a documentos. En lugar de almacenar datos en tablas con filas y columnas fijas, MongoDB guarda cada registro como un documento BSON (Binary JSON). BSON es una extensión binaria de JSON que permite un rango más amplio de tipos de datos (por ejemplo, fechas, objetos binarios, decimales, etc.).

Documentos vs Filas

Característica Base de datos relacional (SQL) MongoDB (NoSQL)
Estructura Esquema fijo, columnas predefinidas Sin esquema previo, cada documento puede tener campos distintos
Relaciones Normalización mediante claves foráneas Incorporación (embedding) o referencias (referencing)
Escalabilidad Escala vertical (añadir más recursos a un servidor) Escala horizontal (agregar más nodos fácilmente)
Consulta SQL (JOINs, GROUP BY, etc.) Consultas basadas en JSON, operadores potentes

Colecciones

Una colección en MongoDB es análoga a una tabla en SQL, pero con una diferencia clave: puede contener documentos de diferentes formas. Imagina una colección users donde algunos documentos tienen campos como nombre, email, edad, mientras que otros también incluyen dirección, teléfono, etc. Todos coexisten sin necesidad de alterar un esquema preexistente.

Configuración rápida del entorno (opcional)

Si querés experimentar con MongoDB localmente, podés instalar el paquete oficial desde mongodb.com/try/download/community. Una vez instalado, el comando mongosh te da acceso a la shell de MongoDB. Para los ejemplos de este artículo no es estrictamente necesario tener un servidor en ejecución; los comandos se muestran junto con la salida esperada, para que podás visualizar cómo se verían.

Si preferís un enfoque sin instalar nada, tenés la opción de usar MongoDB Atlas (el servicio gestionado en la nube de MongoDB) y crear una cuenta gratuita. Los mismos comandos de la shell funcionarán.

Creación de una base de datos y una colección

Una base de datos en MongoDB es un contenedor lógico para colecciones, similar a un esquema en SQL. No creas una base de datos físicamente hasta que insertas el primer documento.

Ejemplo: Crear la base de datos ecommerce y la colección products

// En la shell de MongoDB (mongosh)
use ecommerce

Salida esperada:

switched to db ecommerce

use ecommerce selecciona (o crea) la base de datos ecommerce. Ahora podés comenzar a crear documentos en la colección products:

db.products.insertMany([
  {
    "productId": "p001",
    "name": "Laptop Pro",
    "category": "Electronics",
    "price": 1499.99,
    "stock": 30,
    "tags": ["laptop", "computer", "work"],
    "specs": {
      "cpu": "Apple M2",
      "ram": "16GB",
      "storage": "512GB SSD"
    }
  },
  {
    "productId": "p002",
    "name": "Organic Avocado",
    "category": "Grocery",
    "price": 2.5,
    "stock": 200,
    "tags": ["fruit", "healthy", "organic"],
    "specs": {
      "origin": "California",
      "weight": "150g"
    }
  }
])

Salida esperada (vista al ejecutar db.products.find().pretty()):

{
  "_id": ObjectId("60d5ecf5f2e5c93b2d5e4e5c"),
  "productId": "p001",
  "name": "Laptop Pro",
  "category": "Electronics",
  "price": 1499.99,
  "stock": 30,
  "tags": ["laptop", "computer", "work"],
  "specs": {
    "cpu": "Apple M2",
    "ram": "16GB",
    "storage": "512GB SSD"
  }
}
{
  "_id": ObjectId("60d5f0b5f2e5c93b2d5e4e5d"),
  "productId": "p002",
  "name": "Organic Avocado",
  "category": "Grocery",
  "price": 2.5,
  "stock": 200,
  "tags": ["fruit", "healthy", "organic"],
  "specs": {
    "origin": "California",
    "weight": "150g"
  }
}

Cada documento recibe automáticamente un _id único (ObjectId), que es fundamental para la identidad del documento.

Documentos en MongoDB: más allá del JSON

El uso de BSON permite a MongoDB almacenar una variedad de tipos de datos que van un poco más allá del JSON estándar:

Tipo JSON Tipo BSON equivalente
string String
number Int32 / Int64 / Double
boolean Boolean
null Null
array Array
object Document (embed)
date Date
binary BinData (para archivos)

Por qué es importante el uso de BSON

  • Rendimiento: El formato binario reduce el espacio de almacenamiento y acelera las serializaciones.
  • Tipos adicionales: Puedes guardar fechas, valores decimales o inclusalmente objetos JavaScript (code, symbol).
  • Ordenación y consultas: Algunos tipos, como date, permiten ordenar directamente en la base de datos.

Ejemplo: Insertar un documento con tipos de datos avanzados

db.users.insertOne({
  "username": "jdoe",
  "fullName": "John Doe",
  "isActive": true,
  "loginCount": NumberInt(42),
  "balance": NumberDecimal("123.45"),
  "joinedAt": ISODate("2022-08-15T10:30:00Z"),
  "avatar": BinData(0, "VGhpcyBpcyBhIHRlc3QgYmluYXJ5IGlkAA=="),
  "roles": ["admin", "editor"],
  "profile": {
    "bio": "Desarrollador apasionado",
    "preferences": {
      "theme": "dark",
      "notifications": true
    }
  }
})

Salida esperada (db.users.findOne()):

{
  "_id": ObjectId("60d5f2c5f2e5c93b2d5e4e5e"),
  "username": "jdoe",
  "fullName": "John Doe",
  "isActive": true,
  "loginCount": 42,
  "balance": 123.45,
  "joinedAt": ISODate("2022-08-15T10:30:00Z"),
  "avatar": BinData(0, "..."),
  "roles": ["admin", "editor"],
  "profile": {
    "bio": "Desarrollador apasionado",
    "preferences": {
      "theme": "dark",
      "notifications": true
    }
  }
}

Operaciones CRUD básicas

Aprender MongoDB sin pasar por las operaciones CRUD resultaría incompleto. A continuación, detallamos cada una de ellas con un ejemplo concreto y la salida esperada.

1. Crear (Insertar)

La operación insertOne agrega un único documento; insertMany acepta un array y crea varios.

db.tasks.insertOne({
  "title": "Diseñar prototipo",
  "status": "pending",
  "priority": 3,
  "tags": ["UX", "UI"]
})

Salida esperada:

{
  "acknowledged": true,
  "insertedId": ObjectId("60d5f4c5f2e5c93b2d5e4e5f")
}

2. Leer (Consultar)

Consulta simple

db.tasks.findOne({ "title": "Diseñar prototipo" })

Salida esperada: (lo mismo que insertaste, con el _id agregado)

Consulta con proyección (solo ciertos campos)

db.tasks.find(
  { "status": "pending" },
  { "title": 1, "status": 1, "_id": 0 }
).pretty()

Salida esperada:

{ "title": "Diseñar prototipo", "status": "pending" }

Uso de operadores

db.tasks.find({
  "priority": { "$gte": 3 },
  "tags": "UX"
}).pretty()

Salida esperada: mostrará cualquier documento que cumpla con priority mayor o igual a 3 y que tenga "UX" dentro del array tags.

3. Actualizar

updateOne modifica el primer documento que coincida; updateMany modifica todos los documentos coincidentes.

db.tasks.updateOne(
  { "title": "Diseñar prototipo" },
  { "$set": { "status": "in-progress", "priority": 1 } }
)

Salida esperada:

{
  "acknowledged": true,
  "matchedCount": 1,
  "modifiedCount": 1,
  "upsertedId": null
}

4. Eliminar

db.tasks.deleteOne({ "title": "Diseñar prototipo" })

Salida esperada:

{
  "acknowledged": true,
  "deletedCount": 1
}

Incorporación vs Referencia: Diseño de esquemas

Una de las decisiones más importantes al trabajar con MongoDB es decidir cómo modelar relaciones entre entidades. Los dos enfoques predominantes son:

  1. Incorporación (Embedding): Guardar documentos relacionados dentro de otro documento.
  2. Referencia (Referencing): Guardar una copia del _id de otro documento y mantener ese documento en una colección separada.

Cuándo incorporar

  • Relación uno a muchos donde el documento hijo cambia raramente.
  • El hijo es pequeño, y se accede a él frecuentemente junto con el padre.
  • El padre define el contexto (por ejemplo, un order con sus items).

Cuándo referenciar

  • El documento hijo es grande y cambia regularmente.
  • Hay muchos padres que comparten el mismo hijo (muchos a muchos).
  • Es importante mantener la integridad referencial (aunque MongoDB no aplica claves foráneas de forma nativa, se puede simular).

Ejemplo: Modelo de blog con incorporación

db.posts.insertOne({
  "title": "Introducción a MongoDB",
  "author": "alice",
  "content": "MongoDB es genial...",
  "comments": [
    {
      "user": "bob",
      "text": "¡Excelente artículo!",
      "likes": 5
    },
    {
      "user": "carla",
      "text": "Muy claro.",
      "likes": 2
    }
  ]
})

Salida esperada: se inserta un post con dos comentarios integrados.

Ejemplo: Modelo de blog con referencia

// Primero, crear la colección `comments`
db.comments.insertMany([
  {
    "_id": ObjectId("60d5f6c5f2e5c93b2d5e4e60"),
    "user": "bob",
    "text": "¡Excelente artículo!",
    "likes": 5
  },
  {
    "_id": ObjectId("60d5f7c5f2e5c93b2d5e4e61"),
    "user": "carla",
    "text": "Muy claro.",
    "likes": 2
  }
])

// Luego, el post hace referencia a ellos
db.posts.insertOne({
  "title": "Introducción a MongoDB",
  "author": "alice",
  "content": "MongoDB es genial...",
  "commentIds": [
    ObjectId("60d5f6c5f2e5c93b2d5e4e60"),
    ObjectId("60d5f7c5f2e5c93b2d5e4e61")
  ]
})

Salida esperada: el post incluye un array commentIds con los ObjectIds referenciados.

Nota: Aunque referenciar añade complejidad de consulta (necesitas $lookup para uniones), suele ser más flexible para esquemas en evolución.

Por qué el modelo NoSQL cambia el enfoque de los datos

1. Sin esquema previo

En SQL, typically definís un CREATE TABLE con columnas y tipos fijos. Cambiar ese esquema puede requerir migraciones costosas. MongoDB, en cambio, permite agregar nuevos campos a documentos existentes sin interrupción.

2. Documentos ricos y semiestructurados

Pensá en una aplicación móvil que recibe datos de múltiples fuentes: JSON de APIs externas, logs con campos variables, sensores con lecturas aleatorias. Guardar todo en documentos BSON evita tener que Normalizar datos en múltiples tablas.

3. Escalado horizontal y tolerancia a fallos

nativo

MongoDB está diseñado para ejecución en clústeres replicados. Cada nodo mantiene una copia de los datos, lo que permite escribir en cualquier nodo (con replicación de escrituras) y leer desde el más cercano. Esto contrasta con el escalado vertical tradicional de bases de datos relacionales, que se ve limitado por los recursos de un único servidor.

4. CAP y consistencia eventual

El teorema CAP (Coherencia, Disponibilidad, Tolerancia a particiones) nos dice que un sistema distribuido puede garantizar a lo sumo dos de estos tres aspectos. MongoDB prioriza Consistencia (mediante replicación) y Disponibilidad, pero sacrifica estrictamente la coherencia en escenarios de alta partition. Esto se conoce como consistencia eventual — los lectores pueden ver datos desactualizados por un breve período.

5. Consultas ricas y operadores

Los operadores de consulta de MongoDB permiten realizar filtrados complejos directamente en el servidor, como $regex, $elemMatch, $text, $geoNear. No necesitas escribir uniones SQL o subconsultas; podés expresar lógica en el propio JSON.

6. Flexibilidad en el desarrollo ágil

Cuando los requisitos cambian rápidamente (por ejemplo, un producto necesita agregar un nuevo campo a un perfil de usuario), con SQL necesitarías alterarlos en tiempo de ejecución. Con MongoDB, podés simplemente insertar documentos con ese nuevo campo, y la aplicación seguirá funcionando.

Casos de uso donde MongoDB destaca

Caso de uso Por qué MongoDB es una buena opción
Big Data & Analytics Puede almacenar logs no estructurados, eventos de clickstream y datos de sensores en un solo sitio. Los potentes agregadores ($group, $project) aceleran la obtención de insights.
Administración de contenido (CMS) Contenido variado (imágenes, vídeos, markdown, metadatos) se guarda como documentos flexibles. Sin necesidad de múltiples tablas para diferentes tipos de contenido.
Aplicaciones móviles / IoT Datos en tiempo real de dispositivos, a menudo en JSON. MongoDB puede procesarlos cerca del origen con bajo retardo.
Microservicios Cada servicio puede tener su propia colección, reduciendo acoplamiento. No es necesario gestionar esquemas centralizados.
Dashboards en tiempo real Los cambios se reflejan rápidamente gracias a replicación y operados como $currentDate. Las consultas pueden filtrarse por rangos de tiempo.

Buenas prácticas y recomendaciones

1. Diseña campos consistentes

  • Utiliza camelCase o snake_case de forma consistente en toda la colección.
  • Evita guardar arrays de documentos que nunca vas a consultar juntos; en su lugar, considera incorporar o referenciar.

2. Crear índices para las consultas frecuentes

db.users.createIndex({ "email": 1 })
db.orders.createIndex({ "status": 1, "createdAt": -1 })

Los índices aceleran las búsquedas, pero consumen espacio. Utilízalos con moderación.

3. Validación de esquemas (opcional pero útil)

Puedes usar schemaValidation a nivel de colección para asegurarse de que los documentos cumplan reglas (por ejemplo, price debe ser un número positivo).

db.products.createCollection("products", {
  validator: {
    $and: [
      { "price": { $type: "double", $gte: 0 } },
      { "name": { $type: "string", $maxLength: 100 } }
    ]
  }
})

4. Controla el tamaño de los documentos

MongoDB tiene un límite de documento de 16 MB. Si necesitas algo más grande, considera dividir en múltiples documentos (por ejemplo, con shardKey).

5. Utiliza $inc, $push, $pull para actualizaciones atómicas

db.inventory.updateOne(
  { "productId": "p001" },
  { "$inc": { "stock": -1 } }
)

Esto evita condiciones de carrera en aplicaciones concurrente.

6. Aprovecha la paginación

Siempre devuelve una subconjunto de resultados con limit y skip (o cursor.batchSize). Para grandes volúmenes de datos, considera find().cursor.batchSize(20).

Errores comunes y cómo evitarlos

Error Por qué sucede Cómo solucionarlo
Sobrealimentar un índice Creación indiscriminada de índices sin entender las consultas reales. Revisa las estadísticas de db.collection.stats() y db.collection.aggregate([... { $indexStats: {} }]).
Guardar demasiados datos en un documento Sobrecargar el almacenamiento o rebasar los 16 MB. Divide en documentos más pequeños, usa subcolecciones (mediante prefijo en nombres) o referencia.
Ignorar el _id de ObjectId Pensar que es solo un identificador, no un timestamp. Utiliza $expr o agregación para extraer fecha de creación si es necesario.
Consultas sin índice que causan escaneo de colección Al inicio, las aplicaciones a menudo consultan con campos sin índice. Monitorea explain() para ver el plan de ejecución.
Uso incorrecto de incorporación vs referencia Incorporar todo por simplicidad, pero luego los documentos se vuelven inmanejables. Reevalúa las cardinalidades de relaciones; haz un modelo híbrido.

Resumen y próximos pasos

MongoDB ofrece una alternativa potente y flexible a las bases de datos relacionales. Al almacenar datos en documentos BSON dentro de colecciones, podés modelar información semiestructurada sin necesidad de un esquema fijo. Las operaciones CRUD básicas (insert, find, update, delete) son intuitivas y se expresan en JavaScript, lo que alinea el lenguaje de consulta con el lenguaje de programación.

Entender las diferencias conceptuales — documentos vs filas, incorporación vs referencia, y la filosofía NoSQL de escalado horizontal — te ayuda a decidir cuándo MongoDB es la mejor opción. Los casos de uso típicos abarcan desde aplicaciones web modernas y gestión de contenido hasta analítica de big data e IoT.

Si querés profundizar, podrías explorar:

  • Shardings y particionamiento para manejar conjuntos de datos masivos.
  • Aggregations para pipeline de procesamiento de datos complejos.
  • MongoDB Atlas para usar un clúster gestionado sin preocuparte por la infraestructura.
  • Mecanismos de seguridad como RBAC, encryption-at-rest y TLS.

Con una base sólida en documentos, colecciones y los principios que hacen diferente a NoSQL, estás listo para comenzar a construir aplicaciones escalables y flexibles con MongoDB. ¡Feliz modelado!


Referencias útiles


Sobre el autor

Soy un desarrollador back‑end con más de 10 años de experiencia construyendo sistemas de datos a escala. Me apasiona ayudar a otros a entender conceptos complejos de bases de datos a través de explicaciones prácticas y codebases reales. Si tenés preguntas, sugerencias o un caso de uso específico que te gustaría que cubra, no dudes en contactarme.

Comentarios (0)

Sé el primero en comentar.

Dejá tu comentario