Elección del modelo de datos MongoDB adecuado: documentos incrustados vs. referenciados
Elija documentos incrustados o referenciados en MongoDB según los patrones de acceso, el crecimiento, la consistencia y el comportamiento de actualización.
Elección del modelo de datos correcto en MongoDB: documentos incrustados vs. referenciados
El modelado de datos en MongoDB generalmente se reduce a una pregunta práctica: ¿los datos relacionados deben vivir dentro del mismo documento, o un documento debe hacer referencia a otro? Esta elección afecta la velocidad de lectura, el costo de actualización, el crecimiento del documento y cuánto trabajo de consistencia debe manejar su aplicación.
Esta guía profundiza en las compensaciones entre incrustar documentos dentro de un documento padre y hacer referencia a documentos relacionados en diferentes colecciones. Comprender cuándo y cómo aplicar estas técnicas le permitirá diseñar esquemas MongoDB eficientes y de alto rendimiento adaptados a los patrones de acceso específicos de su aplicación.
Comprensión de las estrategias de modelado de datos en MongoDB
MongoDB organiza los datos en documentos (similares a objetos JSON) almacenados en colecciones. Las relaciones entre estos documentos se pueden modelar utilizando dos patrones principales:
- Incrustación (Desnormalización): Almacenar datos relacionados directamente dentro del documento padre.
- Referencia (Normalización): Almacenar solo una referencia (como un
_id) al documento relacionado en otra colección, similar a una clave foránea.
1. El patrón de incrustación (Desnormalización)
La incrustación implica colocar un documento directamente dentro de otro. Esta técnica es muy favorecida en MongoDB cuando las relaciones de datos son de uno a pocos o cuando los datos relacionados se acceden con frecuencia junto con el documento padre.
Cuándo usar la incrustación
Use el patrón de incrustación cuando:
- Los datos se acceden juntos: Si casi siempre necesita los datos relacionados al consultar el padre, la incrustación minimiza el número de operaciones de base de datos necesarias para obtener el conjunto completo de información.
- Relaciones de uno a pocos: Ideal para relaciones donde la matriz de documentos incrustados permanece relativamente pequeña y predecible (por ejemplo, las últimas 10 actividades de inicio de sesión de un usuario, o los artículos de línea de un pedido).
- La consistencia de datos es crítica: Los datos incrustados son inherentemente consistentes porque residen dentro de un solo documento, simplificando las garantías de atomicidad proporcionadas por las transacciones ACID de un solo documento de MongoDB.
Ejemplo de incrustación
Considere un Producto y sus Reseñas. Si las reseñas se obtienen con frecuencia junto con el producto y el número total de reseñas es manejable:
// Documento de la colección de productos
{
"_id": ObjectId("..."),
"nombre": "SSD de alto rendimiento",
"precio": 129.99,
"reseñas": [
{
"usuario": "Alicia",
"puntuación": 5,
"comentario": "¡La unidad más rápida de todas!"
},
{
"usuario": "Roberto",
"puntuación": 4,
"comentario": "Gran valor."
}
]
}
Desventajas de la incrustación
- Límites de tamaño del documento: Los documentos de MongoDB tienen un límite de tamaño máximo de 16MB. Si la matriz de documentos incrustados crece sin un límite claro, es posible que eventualmente necesite referencias o agrupación.
- Sobrecarga de actualización: Las matrices incrustadas grandes pueden hacer que las actualizaciones sean más costosas y pueden aumentar la contención en el documento padre.
- Duplicación de datos: Si los datos incrustados deben compartirse o mostrarse independientemente del padre, corre el riesgo de duplicación de datos y problemas de consistencia eventual si las actualizaciones no se sincronizan en todas las copias.
2. El patrón de referencia (Normalización)
La referencia imita el concepto de claves foráneas en bases de datos relacionales. En lugar de incrustar los datos relacionados, almacena el _id u otro identificador estable para el documento relacionado. Esto a menudo requiere una segunda consulta, una etapa de agregación $lookup o una unión del lado de la aplicación para recuperar los datos relacionados.
Cuándo usar la referencia
Use el patrón de referencia cuando:
- Relaciones de uno a muchos o muchos a muchos: Cuando un lado de la relación puede crecer indefinidamente (por ejemplo, el número de comentarios en una publicación de blog, o usuarios que pertenecen a muchos grupos).
- Datos compartidos entre múltiples padres: Si la entidad de datos relacionados necesita ser actualizada y accedida de forma independiente por múltiples otros documentos (por ejemplo, un documento
Categoríautilizado por muchos documentosProducto). - Conjuntos de datos grandes: Cuando la incrustación violaría el límite de tamaño de documento de 16MB.
Tipos de referencia
A. Referencias manuales (Uniones del lado de la aplicación)
Almacenar el _id en el documento padre:
// Colección de autores
{
"_id": ObjectId("autor123"),
"nombre": "Juana Pérez"
}
// Colección de libros
{
"_id": ObjectId("libro456"),
"título": "Modelado de datos 101",
"autor_id": ObjectId("autor123") // Referencia
}
Para recuperar el nombre del autor, realiza dos consultas o usa $lookup:
// Ejemplo usando $lookup en el marco de agregación
db.libros.aggregate([
{ $match: { título: "Modelado de datos 101" } },
{
$lookup: {
from: "autores", // Colección a unir
localField: "autor_id", // Campo de los documentos de entrada (libros)
foreignField: "_id", // Campo de los documentos de la colección 'from' (autores)
as: "detalles_autor"
}
}
]);
B. Referencias bidireccionales
Para relaciones bidireccionales, también puede hacer referencia al padre en el documento hijo. Esto facilita la navegación de la relación en ambas direcciones, aunque aumenta la sobrecarga de escritura ya que las actualizaciones deben ocurrir en dos lugares.
Desventajas de la referencia
- Mayor complejidad de consulta: Recuperar datos completamente desnormalizados requiere uniones (ya sea a través del código de la aplicación o
$lookupde MongoDB), que pueden ser más lentas que una sola operación de lectura incrustada. - Gestión de consistencia: Si duplica campos seleccionados de un documento referenciado, como el nombre para mostrar de un autor en un registro de libro, debe actualizar esas copias o aceptar un desfase temporal.
Resumen: Tomar la decisión correcta
La decisión entre incrustación y referencia gira en torno a los patrones de acceso. Pregúntese: ¿Con qué frecuencia se recuperan estos datos relacionados? ¿Con qué frecuencia cambian? ¿Son pequeños o potencialmente masivos?
| Característica / Consideración | Incrustación (Desnormalización) | Referencia (Normalización) |
|---|---|---|
| Rendimiento de lectura | Excelente (Una sola consulta) | Bueno a regular (Requiere uniones) |
| Rendimiento de escritura | Puede ser costoso para documentos padres grandes o populares | A menudo más simple para documentos independientes |
| Límite de tamaño de datos | Limitado por el límite de documento de 16MB | Evita un documento padre enorme, pero aún necesita índices y límites de consulta diseñados cuidadosamente |
| Tipo de relación | Uno a pocos | Uno a muchos, muchos a muchos |
| Consistencia de datos | Alta (Escrituras atómicas) | Gestionada manualmente (Posible desfase) |
Consejo de mejor práctica: Comience incrustando, pivote después
Una estrategia común y efectiva es comenzar incrustando datos que sabe que lee con frecuencia juntos. Esto optimiza para el caso común. Si más adelante encuentra cuellos de botella de rendimiento debido al crecimiento de documentos grandes o la complejidad excesiva de actualización, puede pivotar ese dato específico a su propia colección y cambiar a referencias.
Conclusión
Los esquemas de MongoDB funcionan mejor cuando coinciden con sus consultas reales. Incruste datos que lee juntos y que puede mantener acotados. Haga referencia a datos que crecen de forma independiente, son compartidos por muchos padres o cambian según su propio horario. Antes de decidirse por un modelo, escriba sus principales lecturas y escrituras, luego pruebe esas rutas con tamaños de documento realistas.