Retour
4. Mongoose: Les Relations

Ce cours traite de l'utilisation de Mongoose avec NodeJS pour la gestion des relations entre les modèles et les documents dans une base de données MongoDB.
Nous allons voir les différents types de relations que nous pouvons rencontrer, et comment les definir et les utiliser dans nos model pour créer des structure de données complexes.
Prérequis
Pour suivre cette d'inititaion, vous devez avoir une compréhension de base de la manipulation de données avec MongoDB et de la création de modèles de données avec Mongoose.
- Les Opérations avec Mongoose.js.
Plan du cours
La première partie du cours est une introduction qui rappelle les concepts de modèle et de document, ainsi que la présentation de la notion de relations entre modèles/documents.
Nous aborderons la définition de ce qu'est une relation entre modèles/documents et les raisons pour lesquelles nous devrions les utiliser.
La deuxième partie du cours traite des différents types de relations que nous pouvons rencontrer entre modèles/documents.
Nous allons aborder la relation One-to-One, la relation One-to-Many et la relation Many-to-Many.
Pour chaque type de relation, nous définirons ce que c'est et nous donnerons des exemples concrets.
La troisième partie du cours se concentre sur la mise en place des relations dans Mongoose.
Nous aborderons les références et les sous-documents.
Nous définirons chacun de ces concepts et nous donnerons des exemples concrets.
La quatrième partie du cours se concentre sur les requêtes sur les documents liés.
Nous aborderons les méthodes populate() et les méthodes de jointure.
Pour chacune de ces méthodes, nous définirons ce que c'est et nous donnerons des exemples concrets.
Objectifs
- Comprendre la notion de relations entre modèles/documents et les raisons pour lesquelles elles sont importantes dans la gestion d'une base de données MongoDB.
- Connaître les différents types de relations entre modèles/documents (One-to-One, One-to-Many, Many-to-Many) et savoir les implémenter dans Mongoose.
- Comprendre les différentes options de mise en place des relations dans Mongoose, notamment les références et les sous-documents.
- Savoir utiliser les méthodes populate() et les méthodes de jointure pour interroger les documents liés dans Mongoose.
- Être en mesure d'appliquer les connaissances acquises dans ce cours pour construire des modèles MongoDB complexes avec des relations entre modèles/documents.
Structure du projet
Vous pouvez récuperer le projet le départ sur GitHub.
git clone https://github.com/Djemai-Samy/expressjs-mongoose
Ou récupérer le projet de départ sur GitLab.
git clone https://gitlab.com/tutoriels-dev/expressjs/expressjs-mongoose/-/tree/main
Puis déplacez vous sur le répertoire:
cd ./expressjs-mongoose
Installer toutes les dépendances:
npm install
📦expressjs-mongoose
┣ 📂node_modules
┣ 📜package.json
┗ 📜app.js
Dans app.js:
// Librairie pour intéragir avec une BDD MongoDB
import mongoose from "mongoose";
/**------------------------------------------------------------
* Définition du schéma pour l'exemple
*/
const AuthorSchema = mongoose.Schema({
name: { type: String, required: true, unique:true },
age: { type: Number, required: true },
alive: { type: Boolean, required: true, default: false },
adress:{
country: {type: String, required: true},
city: String
},
books:[
{
title:{type: String, required: true, unique: true},
date: String,
genre: String
}
]
});
/**
* -------------------------------------------------------------
*/
// Instanciation du model pour manipuler les données:
const Author = mongoose.model('Author', AuthorSchema)
/**------------------------------------------------------------
* Connexion à la BDD
*/
// L'URI de la base de données locale
const MONGODB_URI = "mongodb://127.0.0.1:27017/library-queries";
mongoose
.connect(MONGODB_URI)
.then(() => {
// Afficher dans la console que la BDD est connecté
console.log("Connecté à la BDD: library-queries");
})
.catch((err) => {
// Erreur dans le then
console.log("Pas connecté à la BDD");
});
/**
* -------------------------------------------------------------
*/
Lancez l'application en mode developpement:
npm run dev
1. Introduction
1. Rappel des modèles et documents
Avant de parler de relations entre modèles/documents, il est important de rappeler les concepts de modèle et de document dans MongoDB.
Dans MongoDB, un modèle est une représentation de la structure d'une collection de documents.
Un document est un enregistrement dans une collection MongoDB, similaire à une ligne dans une table de base de données relationnelle.
Vous pouvez suivre un cours plus complet sur la définition de modèles et documents avec Mongoose et MongoDb.
2. Notion de relations
Une relation entre documents est une association entre deux ou plusieurs documents qui permet de représenter les liens logiques entre eux.
L'utilisation de relations entre documents est essentielle pour la gestion efficace de données dans une base de données MongoDB.
Les relations permettent de lier les documents ensemble, d'organiser les données de manière logique et de faciliter la recherche et la récupération de données.
Ces relations peuvent être de différents types :
1. One-to-One
La relation One-to-One est une relation dans laquelle chaque document d'un modèle est associé à un et un seul document d'un autre modèle.
Dans cette relation, chaque document est unique et n'a qu'un seul document associé.
Un exemple concret de relation One-to-One est une relation entre un auteur et son adresse.
Dans ce cas, chaque auteur a une adresse unique et chaque adresse est associé à un seul auteur.
Un autre exemple est une relation entre un utilisateur et son profil. Dans ce cas, chaque utilisateur a un profil unique et chaque profil est associé à un seul utilisateur.
2. One-to-Many
Dans une relation One-to-Many (un-à-plusieurs), un document d'un modèle est lié à plusieurs documents d'un autre modèle.
Un exemple concret de relation One-to-Many est une relation entre un auteur et ses livres.
Dans ce cas, chaque auteur a une plusieurs livres et chaque livre est associé à un seul et unique auteur.
3. Many-to-Many
Dans une relation Many-to-Many (plusieurs-à-plusieurs), plusieurs documents d'un modèle peuvent être liés à plusieurs documents d'un autre modèle.
Par exemple, plusieurs utilisateurs peuvent être associés à plusieurs projets, et chaque projet peut avoir une equipe de collaborateurs.
2. Les relations dans Mongoose
Dans cette partie, nous allons voir comment mettre en place des relations entre nos modèles dans Mongoose.
Il existe deux méthodes principales pour cela : les sous-documents et les références.
1. Les sous-documents
Les sous-documents sont des documents imbriqués dans un autre document.
Ils permettent de stocker des données associées à un document principal sans créer de collection distincte pour ces données.
Les sous-documents sont particulièrement utiles pour les relations de type One-to-One et One-to-Many.
Dans l'exemple utilisé representant les auteurs, le champ adresse est considéré comme une relation Ont-to-One.
Le champs books quant à lui une liste et donc considéré comme une relation One-to-Many.
La création d'un sous-document est assez simple en Mongoose.
Il suffit de définir un champ dans le schéma parent avec un type de tableau contenant un schéma imbriqué représentant le sous-document.
Prenons l'exemple d'une application de blog où chaque article est associé à des commentaires.
Dans ce cas, chaque article peut avoir un champ "comments" contenant une liste de sous-documents représentant les commentaires liés à cet article.
Voici un exemple de modèle Mongoose pour représenter un article avec ses commentaires (One-to-Many) :
const PostSchema = new mongoose.Schema({
title: String,
comments: [{
title: String,
content: String
}]
});
Vous pouvez aussi créer un Schema pour les commentaires et l'utiliser dans le Shema de l'article:
const CommentSchema = new mongoose.Schema({
author: String,
content: String
});
const PostSchema = new mongoose.Schema({
title: String,
content: String,
comments: [CommentSchema]
});
2. Les références
Les références sont une technique utilisée pour créer une relation entre des documents dans Mongoose.
Cette technique consiste à stocker une référence à un document d'une collection dans un autre document d'une autre collection.
La référence est stockée sous la forme d'un ObjectId, qui est l'identifiant unique du document dans la collection.
Prenons l'exemple d'un blog.
Nous avons deux collections: les articles et les commentaires.
Chaque article peut avoir plusieurs commentaires, donc il y a une relation One-to-Many entre les articles et les commentaires.
Pour implémenter cette relation avec les références nous avons 3 choix.
3. Dans les deux
Cette technique implique de stocker les références dans les deux modèles parent et enfant.
C'est une technique utile lorsque vous avez besoin d'accéder à la fois aux enfants et aux parents à partir de n'importe quel modèle.
Prenons l'exemple d'un site de commerce électronique où chaque commande est associée à un client et à plusieurs produits.
Dans ce cas, vous pouvez stocker la référence du de l'auteur dans le modèle du livre et stocker les références des livre dans le modèle de l'auteur, ce qui vous permet d'accéder facilement aux au auteurs quand nous récuperons les livres, et aux livres quand nous récupérons les auteurs.
const BookSchema = new mongoose.Schema({
title: String,
content: String,
author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author' }
});
const AuthorSchema = new mongoose.Schema({
title: String,
content: String,
books:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'Book',
}]
});
Cette technique permet une navigation rapide des deux côtés de la relation et une mise à jour facile de l'ensemble de la relation en une seule opération de base de données.
Cependant, elle peut entraîner une duplication de données et un risque de cohérence des données si les références ne sont pas correctement mises à jour.
Il faut faire attention aussi à que la liste des références ne devienne pas trop longue et ne depasse la limite de 16MB par document.
2. Dans le parent
Cette technique implique de stocker la référence dans le modèle parent uniquement.
C'est une technique utile lorsque vous n'avez besoin d'accéder qu'à l'enfant à partir du parent et non l'inverse.
Par exemple, si nous avons un parent "Post" et des enfants "Comment", chaque articles aura une liste de références aux commentaire, ce qui permet de récuperer facilement la liste de commentaire d'un article.
const CommentSchema = new mongoose.Schema({
author: String,
content: String,
});
const PostSchema = new mongoose.Schema({
title: String,
content: String,
comment:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment',
}]
});
Les avantages de cette technique sont qu'elle permet une navigation rapide dans le sens parent vers enfant et évite la duplication de données dans l'enfant.
Toutefois, si vous devez également accéder à l'utilisateur d'une tâches donné, il peut être plus difficile d'obtenir cette information à partir du modèle Task.
Il faut faire attention aussi à que la liste des référence ne deviennet pas trop longue et ne depasse la limite de 16MB par document.
3. Dans l'enfant
Cette technique consiste à stocker la référence du parent dans l'enfant.
Par exemple, si nous avons un parent "Utilisateur" et un enfant "Commentaire", chaque commentaire aura une référence au parent Utilisateur, mais aucun utilisateur ne référencera directement le commentaire.
const CommentSchema = new mongoose.Schema({
author: String,
content: String,
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' }
});
const PostSchema = new mongoose.Schema({
title: String,
content: String
});
3. Opérations sur les document liés
Lorsque nous avons des relations entre des documents dans Mongoose, il est souvent nécessaire d'exécuter des requêtes pour récupérer les données associées.
Mongoose nous fournit une méthode qui permet de facilement récuperer les documents liés.
Reprenons l'exemple de la librairie avec des auteurs et des livres:
const BookSchema = mongoose.Schema({
title:{type: String, required: true, unique: true},
date: String,
genres: [String],
author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author' }
})
const AuthorSchema = mongoose.Schema({
name: { type: String, required: true, unique:true },
age: { type: Number, required: true },
alive: { type: Boolean, required: true, default: false },
adress:{
country: {type: String, required: true},
city: String
},
books:[
{ type: mongoose.Schema.Types.ObjectId, ref: 'Book' }
]
});
1. Ajouter un livre
Dans ce code, nous récupérons l'auteur avec son ID.
Puis nous créons un nouveau livre avec l'ID de l'auteur et ses données.
Ensuite, nous enregistrons le livre dans la base de données
Et mettons à jour l'auteur correspondant en ajoutant l'ID du livre au tableau "books".
Enfin nous enregistrons l'utilisateur mis à jour dans la base de données.
const author = await Author.findById(id).populate('books');
// Créer et enregistrer le livre dans la BDD
const newBook = await Book.create({...bookData, author: author._id });
// ajouter le livre à la liste de l'auteur
author.books.push(newBook._id);
// Enregistrer l'utilisateyr dans la BDD
await author.save()
2. Récuperer les données
La méthode populate() est une méthode Mongoose qui permet de récupérer les données associées à un document lié en effectuant une requête supplémentaire.
Elle permet de remplacer les références aux documents liés par leurs données correspondantes.
Si nous souhaitons récupérer tous les auteurs avec leurs livre correspondants, nous pouvons utiliser la méthode populate(nomDuChamp) sur le modèle Author:
const authors = await Author.find().populate('books')
Vous pouvez aussi utiliser le deuxiemme paramètre facultatif de la méthodes pour séléctionner les champs du modèle Book désiré:
populate(nomDuChamp, select:'champ1 champ2')
Ici nous récupérons tous auteur avec leurs livres contenant quel les champs _id, title et genres et date:
const authors = await Author.find().populate('books', select:'title genres date');
Si nous souhaitons récupérer tous les livres avec l'auteur correspondant, nous pouvons utiliser la méthode populate() sur le model Book:
const books = await Book.find().populate('auhtor', select:'name')
3. Mettre à jour un livre
Il est facile de mettre à jour un livre en passant simplement par son modèle, en supposant avoir sont ID:
const book = await Book.findByIdAndUpdate(bookID, newBook, {new: true});
4. Supprimer un livre
Pour supprimer un livre d'un auteur, nous pouvons utiliser la méthode findByIdAndRemove pour trouver et supprimer le livre spécifié, en supposant avoir son identifiant dans la variable bookID
.
Nous devons également mettre à jour le tableau "books" de l'auteur correspondant en supprimant l'ID du livre, , en supposant avoir son l'identifiant de l'auteur dans la variable id
.
// Supprimer le document livre
const book = await Book.findByIdAndDelete(bookID);
// Enelever la référence du livre dans la liste de l'auteur
const author = await Author.findByIdAndUpdate(id, {$pull: { book.bookID }}, {new: true});
Conclusion
Dans ce cours, nous avons appris comment mettre en place des relations entre des modèles ou documents dans Mongoose, une bibliothèque Node.js pour MongoDB.
Nous avons d'abord examiné les trois types de relations : One-to-One, One-to-Many et Many-to-Many.
Nous avons ensuite examiné les avantages et les inconvénients des références, de l'imbriquement et de la duplication pour créer des relations entre des documents.
Ensuite, nous avons examiné la mise en place des relations avec Mongoose. Nous avons vu comment définir les schémas pour les modèles liés et comment créer des références entre eux.
Enfin, nous avons étudié les requêtes sur les documents liés, en nous concentrant sur la méthode populate() de Mongoose.
Nous avons vu comment utiliser cette méthode pour inclure les données des documents liés dans les résultats des requêtes.
Ce chapitre conclut cette série d'initiation la l'utilisation de Mongoose avec des applications Node.js.
Pour aller plus loin dans l'apprentissage de Mongoose, vous pouvez suivre ce tutoriel pour apprendre à utiliser Mongoose dans des cas plus concrets:
Créer une API RESTful avec Mongoose et Express.
Apprendre à créer une API RESTful avec Mongoose et Express.
Tutoriel pour créer une Todo Liste Fullstack avec React, Express et Mongoose.
Aller plus loin

Mongoose: Introduction
Mongoose est une bibliothèque pour Node.js qui facilite l'utilisation de MongoDB, la base de données NoSQL la plus populaire..
Elle permet de créer des modèles, des schémas et de manipuler les données stockées dans une base de données MongoDB.
Javascript
NodeJS
MongoDB
Mongoose
NoSQL

2. Mongoose: Les Opérations
Dans ce cours, vous apprendrez à créer des modèles, des schémas et à effectuer des opérations CRUD avec Mongoose et ExpressJS.
Vous découvrirez également comment gérer les relations entre les modèles, valider les données et effectuer des recherches complexes.
Javascript
NodeJS
MongoDb
Mongoose
NoSQL

3. Mongoose: Les Opérateurs
Apprendre de comprendre comment effectuer des requêtes sur une base de données MongoDB en utilisant le module Mongoose de Node.js.
À la fin du cours, vous serez en mesure de manipuler les données en utilisant des queries et filtres.
Javascript
NodeJS
Mongoose
MongoDB
NoSQL
Operators
1