Choisir le bon modèle de données MongoDB : Documents intégrés par rapport aux documents référencés
Choisissez des documents MongoDB intégrés ou référencés en fonction des modèles d'accès, de la croissance, de la cohérence et du comportement de mise à jour.
Choisir le bon modèle de données MongoDB : Documents intégrés vs. référencés
La modélisation des données MongoDB se résume généralement à une question pratique : les données liées doivent-elles vivre dans le même document, ou un document doit-il en référencer un autre ? Ce choix affecte la vitesse de lecture, le coût des mises à jour, la croissance des documents et la quantité de travail de cohérence que votre application doit gérer.
Ce guide explore en profondeur les compromis entre l'intégration de documents dans un document parent et la référence à des documents connexes dans différentes collections. Comprendre quand et comment appliquer ces techniques vous permettra de concevoir des schémas MongoDB efficaces et performants, adaptés aux modèles d'accès spécifiques de votre application.
Comprendre les stratégies de modélisation des données MongoDB
MongoDB organise les données en documents (similaires aux objets JSON) stockés dans des collections. Les relations entre ces documents peuvent être modélisées à l'aide de deux modèles principaux :
- Intégration (Dénormalisation) : Stocker les données connexes directement dans le document parent.
- Référencement (Normalisation) : Stocker uniquement une référence (comme un
_id) vers le document connexe dans une autre collection, similaire à une clé étrangère.
1. Le modèle d'intégration (Dénormalisation)
L'intégration consiste à placer un document directement à l'intérieur d'un autre. Cette technique est très prisée dans MongoDB lorsque les relations de données sont de type un-à-quelques ou lorsque les données connexes sont fréquemment consultées avec le document parent.
Quand utiliser l'intégration
Utilisez le modèle d'intégration lorsque :
- Les données sont consultées ensemble : Si vous avez presque toujours besoin des données connexes lors de l'interrogation du parent, l'intégration minimise le nombre d'opérations de base de données nécessaires pour récupérer l'ensemble complet des informations.
- Relations un-à-quelques : Idéal pour les relations où le tableau de documents intégrés reste relativement petit et prévisible (par exemple, les 10 dernières activités de connexion d'un utilisateur ou les articles de commande).
- La cohérence des données est critique : Les données intégrées sont intrinsèquement cohérentes car elles résident dans un seul document, simplifiant les garanties d'atomicité fournies par les transactions ACID mono-document de MongoDB.
Exemple d'intégration
Considérons un Produit et ses Avis. Si les avis sont fréquemment récupérés avec le produit et que le nombre total d'avis est gérable :
// Document de la collection Produits
{
"_id": ObjectId("..."),
"nom": "SSD haute performance",
"prix": 129.99,
"avis": [
{
"utilisateur": "Alice",
"note": 5,
"commentaire": "Le disque le plus rapide jamais vu !"
},
{
"utilisateur": "Bob",
"note": 4,
"commentaire": "Excellent rapport qualité-prix."
}
]
}
Inconvénients de l'intégration
- Limites de taille des documents : Les documents MongoDB ont une taille maximale de 16 Mo. Si le tableau de documents intégrés croît sans limite claire, vous pourriez éventuellement avoir besoin de référencement ou de compartimentage.
- Frais généraux de mise à jour : Les grands tableaux intégrés peuvent rendre les mises à jour plus coûteuses et augmenter la contention sur le document parent.
- Duplication des données : Si les données intégrées doivent être partagées ou affichées indépendamment du parent, vous risquez la duplication des données et des problèmes de cohérence éventuelle si les mises à jour ne sont pas synchronisées sur toutes les copies.
2. Le modèle de référencement (Normalisation)
Le référencement imite le concept de clés étrangères dans les bases de données relationnelles. Au lieu d'intégrer les données connexes, vous stockez le _id ou un autre identifiant stable du document connexe. Cela nécessite souvent une deuxième requête, une étape d'agrégation $lookup ou une jointure côté application pour récupérer les données connexes.
Quand utiliser le référencement
Utilisez le modèle de référencement lorsque :
- Relations un-à-plusieurs ou plusieurs-à-plusieurs : Lorsqu'un côté de la relation peut croître indéfiniment (par exemple, le nombre de commentaires sur un article de blog, ou les utilisateurs appartenant à plusieurs groupes).
- Données partagées entre plusieurs parents : Si l'entité de données connexe doit être mise à jour et consultée indépendamment par plusieurs autres documents (par exemple, un document
Catégorieutilisé par de nombreux documentsProduit). - Grands ensembles de données : Lorsque l'intégration violerait la limite de taille de document de 16 Mo.
Types de référencement
A. Références manuelles (Jointures côté application)
Stockage du _id dans le document parent :
// Collection Auteurs
{
"_id": ObjectId("auteur123"),
"nom": "Jane Doe"
}
// Collection Livres
{
"_id": ObjectId("livre456"),
"titre": "Modélisation de données 101",
"auteur_id": ObjectId("auteur123") // Référence
}
Pour récupérer le nom de l'auteur, vous effectuez deux requêtes ou utilisez $lookup :
// Exemple utilisant $lookup dans le framework d'agrégation
db.livres.aggregate([
{ $match: { titre: "Modélisation de données 101" } },
{
$lookup: {
from: "auteurs", // Collection à joindre
localField: "auteur_id", // Champ des documents d'entrée (livres)
foreignField: "_id", // Champ des documents de la collection 'from' (auteurs)
as: "details_auteur"
}
}
]);
B. Références bidirectionnelles
Pour les relations bidirectionnelles, vous pouvez également référencer le parent dans le document enfant. Cela facilite le parcours de la relation dans les deux directions, bien que cela augmente les frais généraux d'écriture car les mises à jour doivent avoir lieu à deux endroits.
Inconvénients du référencement
- Complexité accrue des requêtes : La récupération de données entièrement dénormalisées nécessite des jointures (soit via le code de l'application, soit via
$lookupde MongoDB), ce qui peut être plus lent qu'une seule opération de lecture intégrée. - Gestion de la cohérence : Si vous dupliquez certains champs d'un document référencé, comme le nom d'affichage d'un auteur sur un enregistrement de livre, vous devez mettre à jour ces copies ou accepter un état temporairement obsolète.
Résumé : Faire le bon choix
La décision entre l'intégration et le référencement tourne autour des modèles d'accès. Demandez-vous : À quelle fréquence ces données connexes sont-elles récupérées ? À quelle fréquence changent-elles ? Sont-elles petites ou potentiellement massives ?
| Fonctionnalité / Considération | Intégration (Dénormalisation) | Référencement (Normalisation) |
|---|---|---|
| Performance en lecture | Excellente (Requête unique) | Bonne à passable (Nécessite des jointures) |
| Performance en écriture | Peut être coûteuse pour les documents parents volumineux ou chauds | Souvent plus simple pour les documents indépendants |
| Limite de taille des données | Limitée par la limite de document de 16 Mo | Évite un document parent énorme, mais nécessite toujours des index et des limites de requêtes conçus avec soin |
| Type de relation | Un-à-quelques | Un-à-plusieurs, Plusieurs-à-plusieurs |
| Cohérence des données | Élevée (Écritures atomiques) | Gérée manuellement (Obsolescence potentielle) |
Conseil de bonne pratique : Commencez par l'intégration, pivotez plus tard
Une stratégie courante et efficace consiste à commencer par intégrer les données que vous savez être fréquemment lues ensemble. Cela optimise le cas courant. Si vous rencontrez plus tard des goulots d'étranglement de performance dus à une croissance importante des documents ou à une complexité excessive des mises à jour, vous pouvez pivoter ces données spécifiques dans leur propre collection et passer au référencement.
À retenir
Les schémas MongoDB fonctionnent mieux lorsqu'ils correspondent à vos requêtes réelles. Intégrez les données que vous lisez ensemble et que vous pouvez maintenir dans des limites. Référencez les données qui croissent indépendamment, sont partagées par de nombreux parents ou changent selon leur propre calendrier. Avant de vous arrêter sur un modèle, notez vos principales lectures et écritures, puis testez ces chemins avec des tailles de documents réalistes.