Patrones de Modelado NoSQL
Guia practica de modelado NoSQL: embebido vs referenciado, diseno basado en patrones de acceso, y patrones para MongoDB, DynamoDB, Cassandra y Redis.
Overview
Las bases de datos NoSQL abandonan el modelo rigido de tabla-fila en favor de esquemas flexibles optimizados para patrones de acceso especificos. Almacenes de documentos (MongoDB), clave-valor (Redis), columnas anchas (Cassandra, DynamoDB) y grafos (Neo4j) tienen principios de modelado diferentes. La regla clave: modela para tus consultas, no para entidades normalizadas. Comienza con los patrones de lectura y escritura que tu aplicacion necesita, luego disena el esquema para soportarlos eficientemente.
When to Use
-
For alternatives, see NoSQL Database Selection — MongoDB, DynamoDB, Cassandra.
-
El esquema evoluciona frecuentemente y no puede migrarse facilmente
-
Los patrones de lectura son bien conocidos y deben servirse en una sola consulta
-
Se requiere escalado horizontal mas alla de lo que proporcionan bases relacionales
-
Los datos son naturalmente jerarquicos o de tipo grafo
-
Necesidades extremas de rendimiento o baja latencia justifican almacenes especializados
Embebido vs Referenciado
| Enfoque | Mejor Para | Compromiso |
|---|---|---|
| Embebido | Uno-a-pocos, datos leidos juntos, raramente actualizados independientemente | Documentos mas grandes, duplicacion en actualizacion |
| Referenciado | Uno-a-muchos, crecimiento ilimitado, actualizaciones independientes | Requiere joins a nivel de aplicacion |
// MongoDB: Embebido (orden con items)
{
_id: "order-001",
customerId: "cust-123",
items: [
{ productId: "p1", name: "Widget", qty: 2, price: 10.00 },
{ productId: "p2", name: "Gadget", qty: 1, price: 25.00 }
],
total: 45.00
}
// MongoDB: Referenciado (colecciones separadas)
// coleccion orders
{ _id: "order-001", customerId: "cust-123", itemIds: ["li-1", "li-2"] }
// coleccion line_items
{ _id: "li-1", productId: "p1", name: "Widget", qty: 2, price: 10.00 }
{ _id: "li-2", productId: "p2", name: "Gadget", qty: 1, price: 25.00 }
Diseno de Tabla Unica en DynamoDB
// DynamoDB: Tabla unica con GSI sobrecargado
{
"PK": "USER#123",
"SK": "PROFILE",
"name": "Alice",
"email": "alice@example.com"
}
{
"PK": "USER#123",
"SK": "ORDER#001",
"total": 45.00,
"status": "shipped"
}
{
"PK": "ORDER#001",
"SK": "DETAIL",
"items": [...]
}
// Consultar todas las ordenes de un usuario
Query PK = "USER#123" AND begins_with(SK, "ORDER#")
// Consultar detalles de orden
Query PK = "ORDER#001"
Patron de Fila Ancha en Cassandra
// Datos de series temporales: una fila por sensor, columnas para buckets de tiempo
CREATE TABLE sensor_readings (
sensor_id UUID,
day DATE,
hour INT,
minute INT,
temperature DOUBLE,
humidity DOUBLE,
PRIMARY KEY ((sensor_id, day), hour, minute)
) WITH CLUSTERING ORDER BY (hour DESC, minute DESC);
// Consulta: ultimas 24 horas de un sensor
SELECT * FROM sensor_readings
WHERE sensor_id = ? AND day >= ?;
Patrones Redis
# Tabla de clasificacion con sorted sets
import redis
r = redis.Redis()
r.zadd('leaderboard:2024', {'alice': 1500, 'bob': 1200, 'charlie': 1800})
top_players = r.zrevrange('leaderboard:2024', 0, 9, withscores=True)
# Rate limiter con ventana deslizante
pipe = r.pipeline()
pipe.zremrangebyscore('rate:user:123', 0, time.time() - 60)
pipe.zcard('rate:user:123')
current_count = pipe.execute()[1]
if current_count < 100:
r.zadd('rate:user:123', {str(time.time()): time.time()})
Common Mistakes
- Aplicar modelado relacional a NoSQL — normaliza para consistencia en SQL; desnormaliza para lecturas en NoSQL
- Arreglos ilimitados — embeber una lista que crece para siempre causa hinchazon de documentos/columnas
- Ignorar patrones de acceso — los esquemas NoSQL deben ser guiados por consultas, no entidades
- Sin estrategia de paginacion — conjuntos de resultados grandes necesitan paginacion basada en cursor o keyset
- Tratar todas las bases NoSQL igual — el embebido de MongoDB, tabla unica de DynamoDB y filas anchas de Cassandra son enfoques fundamentalmente diferentes
Troubleshooting
- Query is slow after an index change: check execution plans and cardinality estimates. Rebuild statistics and verify the index is being used.
- Replication lag grows: Split large writes and consider parallel replication.
- Connections exhausted: review connection pool size, idle timeouts, and leaked connections.
- Backup takes too long: enable compression, incremental backups, and off-peak scheduling.
- Deadlocks in high concurrency: access tables and rows in a consistent order.
Temas Avanzados
Escenario Detallado: Modelado de Blog con MongoDB
Sistema: Plataforma de blog con 1M posts, 10M comentarios
Patrones de acceso:
1. Leer post completo con autor y comentarios (90% de lecturas)
2. Listar posts por autor
3. Listar posts por tag
4. Buscar posts por texto
Modelo embebido (post + comentarios):
db.posts.insertOne({
_id: "post-001",
title: "Patrones NoSQL en la practica",
slug: "patrones-nosql-practica",
author: {
id: "user-123",
name: "Ana Garcia",
avatar: "/avatars/ana.jpg"
},
tags: ["nosql", "mongodb", "modelado"],
content: "Contenido del post...",
comments: [
{
id: "c-001",
author: "Carlos",
text: "Excelente articulo",
createdAt: ISODate("2026-03-01"),
likes: 12
},
{
id: "c-002",
author: "Beatriz",
text: "Tengo una pregunta",
createdAt: ISODate("2026-03-02"),
likes: 3
}
],
commentCount: 2,
publishedAt: ISODate("2026-03-01"),
updatedAt: ISODate("2026-03-05")
});
Indices:
db.posts.createIndex({ slug: 1 }, { unique: true });
db.posts.createIndex({ "author.id": 1, publishedAt: -1 });
db.posts.createIndex({ tags: 1, publishedAt: -1 });
db.posts.createIndex({ title: "text", content: "text" });
Consultas:
// Post completo por slug (una sola consulta)
db.posts.findOne({ slug: "patrones-nosql-practica" });
// Posts por autor (paginados)
db.posts.find({ "author.id": "user-123" })
.sort({ publishedAt: -1 })
.skip(0)
.limit(10);
// Posts por tag
db.posts.find({ tags: "mongodb" })
.sort({ publishedAt: -1 })
.limit(20);
Cuando embeber vs referenciar comentarios:
| Criterio | Embeber | Referenciar |
|----------|---------|-------------|
| Comentarios por post | < 100 | > 1000 |
| Frecuencia de actualizacion | Baja | Alta |
| Tamano del comentario | Corto | Largo |
| Necesidad de query independiente | No | Si |
Patron de migracion: empezar embebido, migrar a referenciado si:
- El documento excede 16MB (limite de MongoDB)
- Los tiempos de escritura se degradan
- Necesitas paginar comentarios independientemente
Migracion:
1. Crear coleccion comments separada
2. Mover comentarios existentes con un script
3. Actualizar la app para leer de comments
4. Mantener commentCount en el post para evitar COUNT queries
Lecciones aprendidas:
- Embeber cuando los datos se leen juntos y son pocos
- Referenciar cuando la lista crece sin limite
- Mantener contadores desnormalizados para evitar COUNT
- Los indices de texto eliminan necesidad de Elasticsearch para busqueda simple
Como manejo consistencia eventual entre colecciones referenciadas?
Usa el patron Outbox: cuando actualices una coleccion, escribe un evento en una coleccion outbox dentro de la misma transaccion. Un proceso separado lee el outbox y actualiza las colecciones dependientes. Para MongoDB, usa transacciones multi-documento (disponibles desde 4.0 con replica sets). Si no necesitas consistencia inmediata, usa change streams para reaccionar a cambios y actualizar vistas desnormalizadas.
End of document. Review and update quarterly.
Lectura Adicional
- Documentación oficial: consulta la referencia actualizada del framework o herramienta utilizada.
- Guías relacionadas: explora las guías de cassandra y data-modeling para profundizar.
- Patrones complementarios: revisa los patrones de diseño aplicables a tu stack tecnológico.
- Postmortems públicos: estudia incidentes reales de equipos que enfrentaron problemas similares en producción.
Notas de Producción
- Despliega gradualmente usando canary o blue-green para detectar regresiones temprano.
- Configura alertas para errores, latencia p99 y tasa de fallos antes de habilitar en producción.
- Documenta el rollback en el runbook; prueba el procedimiento en staging al menos una vez por trimestre.
- Revisa logs estructurados con correlation IDs para trazar requests end-to-end en incidentes.
Puntos Clave
- Aplica patrones de modelado nosql cuando necesites una solución práctica para tu caso de uso.
- Monitorea el rendimiento después de implementar; mide latencia, errores y uso de recursos antes y después.
- Revisa la sección de Troubleshooting ante errores comunes; la mayoría tienen causa raíz documentada con solución.
- Mantén dependencias actualizadas y ejecuta tests en CI para prevenir regresiones en producción.
Errores Comunes en Producción
- Tratar la guía como un checklist para completar una vez en lugar de una práctica por evolucionar.
- Adoptar cada recomendación de golpe en lugar de comenzar con un cambio medido.
- Saltar la evaluación de madurez e imponer prácticas avanzadas a un equipo no preparado.
- No actualizar runbooks y expectativas de guardia al introducir nuevas prácticas.
- Ignorar datos reales de incidentes al priorizar qué partes de la guía aplicar primero.
- No asignar un responsable que revise decisiones trimestralmente.
- Copiar ejemplos sin adaptarlos a las herramientas y restricciones reales del equipo.
- Olvidar medir resultados antes de agregar la siguiente mejora.
Preguntas frecuentes
¿Cómo empiezo con esto en un proyecto existente?
Empieza con una parte pequeña y aislada de tu codebase. Aplica los conceptos de esta guía a un módulo o servicio. Mide el impacto, luego expande a otras áreas.
¿Qué herramientas necesito?
Las herramientas mencionadas throughout esta guía se listan en cada sección. La mayoría son open-source y ampliamente adoptadas. Consulta los recursos relacionados para instrucciones de setup.
¿Cómo mido el éxito después de implementar esto?
Define métricas claras antes de empezar: benchmarks de rendimiento, tasas de error o indicadores de mantenibilidad. Compara antes y después. Itera basándote en datos, no en suposiciones.
Recursos Relacionados
Guía de Diseño de Bases de Datos
Guía práctica para diseñar bases de datos relacionales con normalización, indexación y modelado de relaciones.
GuideBases de Datos de Series Temporales
Guia practica de bases de datos de series temporales: cuando usar un TSDB especializado, modelo de datos, politicas de retencion, y elegir entre InfluxDB, TimescaleDB y ClickHouse.
GuideBases de Datos de Grafos
Guia practica de bases de datos de grafos: modelo de grafo de propiedades, lenguaje Cypher, patrones de modelado y cuando elegir Neo4j sobre bases relacionales.
GuideACID vs BASE — Modelos de Consistencia Explicados
Guía práctica comparando modelos de consistencia ACID y BASE: cuándo elegir consistencia fuerte, cuándo aceptar consistencia eventual y cómo cada uno afecta el diseño del sistema.
GuideBases de Datos Vectoriales
Guia practica de bases de datos vectoriales: embeddings, busqueda por similitud, vecinos aproximados mas cercanos, y elegir entre Pinecone, Weaviate, pgvector y Chroma.