Patrones de modelado de datos en MongoDB | Nicolás Garzón
Inicio Wiki MongoDB Patrones de modelado Volver a MongoDBMongoDB
Patrones de modelado Reúne patrones de modelado documental para relaciones, crecimiento, versiones, contadores, snapshots y datos históricos según los access patterns del sistema.
Última actualización Actualizada 25 de jul de 2026
Los patrones de modelado documentan soluciones recurrentes para fuerzas como crecimiento, lecturas frecuentes, datos derivados, variabilidad y outliers. No son plantillas obligatorias: cada patrón debe justificar qué problema resuelve, qué coste introduce y cuándo dejaría de funcionar.
Nota anteriorGridFS y archivos Nota siguiente Árboles y jerarquías Texto
Copiar problema del workload
→ fuerzas y límites
→ patrón candidato
→ invariantes y coste
→ mediciónConvierte atributos variables en elementos uniformes:
JavaScript
Copiar {
name : 'Laptop' ,
attributes : [
{ key : 'ramGb' , value : 16 } ,
{ key : 'storageGb' , value : 512 }
]
} Útil para catálogos heterogéneos y búsquedas sobre claves dinámicas. Costes:
índices multikey;
pérdida de tipado específico;
validación más compleja;
queries menos directas;
riesgo de duplicar keys.
No lo uses cuando el conjunto de campos es estable y central para el dominio.
Agrupa eventos acotados por tiempo o capacidad:
JavaScript
Copiar {
sensorId,
hour : ISODate ( '2026-07-24T12:00:00Z' ) ,
measurements : [ ] ,
count : 340
} Reduce cantidad de documentos y overhead. Requiere límites, concurrencia al llenar buckets, política para datos tardíos y estrategia de cierre.
Time series collections implementan una optimización especializada; compara antes de construir buckets manuales.
Guarda un valor derivado que sería costoso recalcular:
JavaScript
Copiar {
productId,
reviewCount : 421 ,
averageRating : 4.6
} Debe existir source of truth y reconciliación. Opciones de actualización:
misma operación o transacción;
Change Stream;
outbox y worker;
job periódico;
recomputación completa.
Define staleness aceptable.
Duplica algunos campos de una entidad referenciada para evitar joins frecuentes:
JavaScript
Copiar {
orderId,
customer : {
id : customerId,
nameAtPurchase : 'Laura Gómez'
}
} Puede representar snapshot histórico o copia sincronizada. Son semánticas distintas:
snapshot no cambia;
extended reference actual debe propagarse.
Guarda junto al documento principal solo el subconjunto más consultado:
JavaScript
Copiar {
productId,
latestReviews : [ ] ,
reviewCount : 1280
} El conjunto completo vive en otra colección. Aporta lectura rápida y controla tamaño, pero exige mantener subset y source of truth coherentes.
La mayoría de documentos usa el modelo simple; los casos extremos se marcan y separan.
JavaScript
Copiar {
customerId,
recentOrders : [ ] ,
hasOverflow : true
} Evita diseñar todo el sistema para pocos outliers, pero introduce dos caminos de lectura y migración al superar el límite.
Documentos de varios subtipos comparten una colección:
JavaScript
Copiar {
type : 'cardPayment' ,
amount,
card : { brand : 'visa' , last4 : '4242' }
} JavaScript
Copiar {
type : 'cashPayment' ,
amount,
cash : { received : 50000 }
} Es correcto si comparten lifecycle y access patterns. Necesita discriminator, validation por variante e índices que no se vuelvan inútiles para la mayoría.
Añade versión para evolucionar documentos:
JavaScript
Copiar {
schemaVersion : 3 ,
} Los lectores soportan versiones durante transición; los writers producen la nueva. El número no reemplaza una migración ni debe incrementarse por cada cambio irrelevante.
Algunas métricas aceptan estimaciones para reducir coste:
conteos aproximados;
sampling;
sketches;
actualización por lotes;
cachés con TTL.
Debe mostrarse como aproximación y contar con proceso de reconciliación cuando el dato exacto importa.
Reserva estructura o capacidad esperada para evitar crecimiento repetido en ciertos workloads. Puede desperdiciar espacio y acoplar el modelo a un máximo artificial. Úsalo solo con evidencia.
Conserva una versión actual y revisiones históricas:
Texto
Copiar currentPolicies
policyRevisionsEvita un array ilimitado dentro del documento principal. Define quién crea revisiones, retención, comparación y restauración.
Un patrón no obliga a consolidar todo. Separa colecciones cuando existen:
lifecycle distinto;
escalado diferente;
permisos diferentes;
retención diferente;
queries independientes;
límites de crecimiento.
Para cada patrón registra:
access pattern;
cardinalidad normal y outlier;
frecuencia de reads/writes;
source of truth;
consistencia requerida;
índices;
failure modes;
migración de entrada y salida;
observabilidad;
alternativa más simple.
Una solución puede combinar:
Texto
Copiar extended reference
+ subset
+ computedCada combinación añade invariantes. No acumules patrones hasta que el schema sea imposible de explicar.
Un subset queda desactualizado.
El outlier vuelve al tamaño normal.
Atributos contienen tipos incompatibles.
Un computed counter se duplica por retry.
Un polymorphic type desconocido llega a un lector antiguo.
El bucket recibe eventos fuera de orden.
Una copia “actual” se trata como snapshot.
aplicar patrones por nombre;
no establecer máximos;
duplicar sin source of truth;
ocultar staleness;
usar attribute pattern para todos los campos;
mantener revisiones ilimitadas embebidas;
no planear reconciliación;
combinar demasiados patrones.
Construye documentos típicos y outlier.
Ejecuta queries principales.
Simula retries y fallos.
Mide tamaños.
Revisa índices.
Prueba migración de límite.
Rompe el proceso de propagación.
Ejecuta reconciliación.
Prueba versiones antiguas.
Documenta la salida del patrón.
Los patrones son nombres para trade-offs recurrentes, no recetas. Attribute maneja variabilidad, bucket agrupa eventos, computed materializa cálculos, extended reference duplica datos útiles, subset controla lecturas y outlier separa extremos. Cada uno necesita límites, source of truth y reparación.
Comprueba lo aprendido
¿Qué problema resuelve subset?
¿Qué diferencia existe entre snapshot y extended reference sincronizada?
¿Qué coste tiene attribute pattern?
¿Cuándo usarías outlier pattern?
¿Qué necesita todo computed field?
¿Por qué no aplicar patrones por nombre?