Retour
2. Express + 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.
Déscription
Le cours sur les modèles avec Mongoose est destiné à tous ceux qui souhaitent approfondir leurs connaissances dans l'utilisation de cette bibliothèque pour la création d'applications web.
Les modèles Mongoose sont une abstraction de la base de données MongoDB et permettent de simplifier l'interaction avec la base de données.
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.
Prérequis
Pour suivre cette serie d'inititaion, vous devez avoir une bonne compréhension du langage JavaScript et des connaissances de base en développement web, y compris la création de sites web statiques et dynamiques:
- Initiation au language Javascript.
- Initiation à la programmation serveur avec NodeJS.
Il faut aussi avoir des connaissances dans la création d'application avec Express.js:
- Initiation à la librairie Express.js.
Objectifs
À la fin de ce chapitre, vous serez en mesure de :
- Créer des modèles Mongoose
- Définir des schémas de validation
- Réaliser des opérations CRUD avec Mongoose et ExpressJS
- Gérer les relations entre les modèles
- Effectuer des recherches complexes dans la base de données MongoDB
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
📦expressjs-mongoose
┣ 📂node_modules
┣ 📜package.json
┗ 📜app.js
Dans app.js:
import express from "express";
// Librairie pour intéragir avec une BDD MongoDB
import mongoose from "mongoose";
// L'URI de la base de données locale
const MONGODB_URI = "mongodb://127.0.0.1:27017/library";
// Le port de l'application
const PORT = 3001;
// Instanciation d'express
const app = express();
// Utilisation du middleware pour parser le JSON
app.use(express.json());
/**------------------------------------------------------------
* Connexion à la BDD et
* Lacement du serveur
*/
mongoose
.connect(MONGODB_URI)
.then(() => {
// Afficher dans la console que la BDD est connecté
console.log("Connecté à la BDD: library");
// Lancer le serveur sur le port sépcifié plus haut
app.listen(PORT, () => {
console.log("Serveur lancé sur le port : " + PORT);
});
})
.catch((err) => {
// Erreur dans le then
console.log("Pas connecté à la BDD");
console.log("Serveur pas lancé");
console.log(err);
});
/**
* -------------------------------------------------------------
*/
Puis déplacez vous sur le répertoire:
cd ./expressjs-mongoose
Installer toutes les dépendances:
npm install
Lancez l'application en mode developpement:
npm run dev
1. Les Schemas et les Models
Le modèle est une abstraction qui représente un type de document dans MongoDB.
Il définit les propriétés et les comportements des documents stockés dans la collection.
Les schémas MongoDB sont utilisés pour définir les règles de validation des données stockées dans un modèle.
Ils définissent les types de données, les contraintes et les options de validation pour les champs d'un document.
1.1 Définition des schémas
Les schémas sont des structures qui définissent la forme des documents stockés dans une collection MongoDB.
Les schémas définissent également les types de données et les contraintes pour chaque champ de document.
Avec Mongoose, il est facile de définir des schémas avec des propriétés et des valeurs par défaut.
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
}
]
});
Dans cet exemple, le schéma a quatre champs:
- "name": Champs de type chaine de caratcère, obligatoire et unique dans la collection
- "age": Champs de type nombre et obligatoire
- "alive": Champ de type boolean, obligatoire, faux par défaut
- "adress": Objet avec deux champs:
- country: Champ de type chaine de caractère obligatoire
- city: Champ de type chaine de caractères non obligatoire
- books: Champs de type liste/tableau d'objets:
- title: Champs de type chaine de caractères, obligatoire
- date: Champs de type chaine de caractères
- genre: Champs de type chaine de caractères
1.2 Définition des modèles
Les modèles Mongoose sont des classes qui représentent des documents de MongoDB.
Les modèles sont créés à partir des schémas et peuvent être utilisés pour effectuer des opérations CRUD avec la base de données.
const Author = mongoose.model('Author', AuthorSchema);
Ce model est objet contenant plusieurs méthodes et propriétés pour interagir avec la collection athors, créer dans la base de données.
Nous pouvons maintenant l'utiliser dans nos routes pour éffectuer des opération pour créer, lire mettre à jour et supprimer les documents de la collection athors.
2. Les opérations
Avec les modèles Mongoose, il est facile de réaliser les opérations CRUD (Create, Read, Update, Delete) dans une base de données MongoDB en utilisant ExpressJS. Nous allons maintenant voir comment réaliser ces opérations avec Mongoose et ExpressJS.
1. Création de données
Pour créer un document dans une collection, nous devons créer une instance du modèle correspondant.
Nous pouvons ensuite définir les valeurs des propriétés de ce document et l'enregistrer dans la base de données.
app.post('/authors', async (req, res) => {
const author = new Author(req.body);
try {
await author.save();
res.json(author);
} catch (error) {
res.status(500).json({message: "Erreur serveur"});
}
});
Dans cet exemple, nous définissons une route POST qui va créer un nouveau document dans la collection "authors".
Nous créons une instance du modèle User en utilisant les données du corps de la requête (req.body), puis nous l'enregistrons dans la base de données avec la méthode save().
Si l'enregistrement est réussi, nous renvoyons le document créé. Sinon, nous renvoyons une réponse d'erreur 500 avec le message d'erreur.
Dans la base de données, vous retrouverez l'utilosateur sous se fomrat:
Nous pouvons aussi utilisé la méthode create du modèle pour créer et enregistrer l'autheur en une seule instruction:
app.post('/authors', async (req, res) => {
try {
// Créer un auteur en utilisant les donnée du body
const newAuthor = await Author.create(req.body);
// Retourner le nouvel auteur
res.status(200).json(newAuthor);
} catch (error) {
// Retourner une erreur si la validation n'est pas passé
res.status(500).json({ message: "Erreur serveur" });
}
});
2. Lecture de données
Pour lire des données à partir d'une collection, nous pouvons utiliser la méthode find() du modèle correspondant.
Cette méthode retourne touts les élement d'une collection:
app.get('/authors', async (req, res) => {
try {
// récuperer tous les auteurs
const authors = await Author.find();
// Retourner la liste d'auteurs
res.status(200).json({ authors });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
Dans cet exemple, nous définissons une route GET qui va renvoyer tous les documents de la collection "author".
Nous utilisons la méthode find() du modèle User pour récupérer tous les documents et nous renvoyons les résultats en réponse.
Si une erreur se produit lors de la récupération des données, nous renvoyons une réponse d'erreur 500 avec le message d'erreur.
Si nous voulons récuperer un auteur avec son identifiant _id, nous pouvons utilisé la méthodes findById:
app.get('/authors/:id', async (req, res) => {
try {
// récuperer l'auteur avec son identifient unique
const author = await Author.findById(req.params.id);
// Si l'auteur n'existe pas, retourner status 404
if (!author) {
return res.status(404).json({ message: "Auteur introuvable" });
}
// Si l'auteur existe, retourner l'auteur avec status 200
res.status(200).json({ author });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
Nous avons une route ExpressJS qui utilise la méthode findById() pour chercher un utilisateur par son identifiant.
Nous récupérons le nom de l'utilisateur dans les paramètres de la requête et nous passons ce nom comme filtre dans la méthode findById().
Si aucun utilisateur n'est', nous retournons une erreur 404, sinon nous renvoyons l'auteur trouvé.
3. Mise à jour de données
Pour mettre à jour un document dans une collection, nous devons d'abord le récupérer à partir de la base de données, modifier ses propriétés et l'enregistrer à nouveau.
Pour cela nous pouvons utiliser la méthodes findByIdAndUpdate, qui permet de faire les trois opération en une seule instruction:
app.put('/users/:id', async (req, res) => {
// Récuperer l'auteur dans la BDD, le mettre à jour et le retourner
const auteur = await Author.findByIdAndUpdate(req.params.id, req.body, { new: true });
// Si l'auteur n'existe pas, retourner 404
if (!auteur) {
return res.status(404).json({ message: "Auteur Introuvable" });
}
// Si l'auteur existe, retourner l'auteur avec status 200
res.status(200).json({ auteur });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
Dans cet exemple, nous définissons une route PUT qui va modifier les données du documents de la collection "author", dont l'id correspond au paramètre dans l'url.
Nous utilisons la méthode findByIdAndUpdate() du modèle Auteur pour récupérer le document, le modifieret l'enregistrer dans la BDD. Dans les options, nous précisant que nous voulons récuperer l'auteur mis à jour avec la clé new: true.
Si l'auteur n'existe pas, nous retournons un réponse avec le status 404.
Sinon nous retournons l'auteur mis à jour.
Si une erreur se produit lors de la récupération des données, nous renvoyons une réponse d'erreur 500 avec le message d'erreur.
4. Suppression de données
Pour supprimer des données avec Mongoose et ExpressJS, vous pouvez utiliser la méthode findByIdAndDelete() pour supprimer un seul document qui correspond à un l'id fournit en paramètre.
// Route pour supprimer un utilisateur par son identifiant
app.delete("/:id", async (req, res) => {
try {
// Récuperer l'aueteur avec son ID et le supprimer
const result = await Author.findByIdAndDelete({ _id: req.params.id });
// Si aucun élément n'a été supprimer/auteur n'existe pas, retourner réponse 404
if (result.deletedCount === 0) {
return res.status(404).json({ message: "Auteur introuvable" });
}
// Si l'auteur existe, retourner lun message avec status 200
res.status(200).json({ message: "Auteur supprimé" });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Erreur serveur" });
}
});
Dans cet exemple, nous avons une route ExpressJS qui utilise la méthode deleteOne() pour supprimer un utilisateur par son identifiant.
Nous récupérons l'identifiant de l'utilisateur dans les paramètres de la requête et nous passons cet identifiant comme filtre dans la méthode deleteOne().
Si aucun utilisateur ne correspond au filtre, nous retournons une erreur 404, sinon nous renvoyons un message indiquant que l'utilisateur a été supprimé.
5. Opérations sur les listes
Afun de manipuler les données dans une liste, Mongoose nous offre plusiseurs solutions.
3. Opérations sur les listes
Afun de manipuler les données dans une liste, Mongoose nous offre plusiseurs solutions.
Nous pouvons récuperer l'auteur et manipuler la liste avec des méthodes avant d'enregistrer l'auteur dans la base données.
Ou utiliser des opérateurs afin de récuperer manipuler liste et enregistrer l'utilisateur en une seule instruction.
1. Ajout d'un élément
Pour ajouter un livre, vous devez tout d'abord récupérer l'auteur par son id, puis pousser un nouveau livre dans la liste des livres de l'auteur avec la méthode push.
app.post('/authors/:id/books', async (req, res) => {
try {
// Récuperer l'aurteur avec son ID
const author = await Author.findById(req.params.id);
// Si l'auteur n'existe pas, retourner 404
if (!author) return res.status(404).json({ message: "Auteur introuvable" });
//ajouté un element a la liste books
author.books.push(req.body);
// Met à jour l'auteur dans la BDD
await author.save();
// Si l'auteur existe, retourner l'auteur avec status 200
res.status(200).json({ author });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
Mongoose offre une méthode nommée findByIdAndUpdate qui permet de trouver l'auteur avec son id, ajouté un élément dans la liste grâce à l'opérateur push et à récuperer l'auteur mis à jour avec l'option new:true.
app.post('/authors/:id/books', async (req, res) => {
try {
// Récuperer l'aurteur avec son ID, ajouté un element a la liste books, et le retourner
const author = await Author.findByIdAndUpdate(
req.params.id, //L'identifient de l'auteur
{ $push: { books: req.body } }, // Ajouté le livre
{ new: true } // Retourner l'auteur mis à jour
);
// Si l'auteur n'existe pas, retourner 404
if (!author) return res.status(404).json({ message: "Auteur introuvable" });
// Si l'auteur existe, retourner l'auteur avec status 200
res.status(200).json({ author });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
2. Récuperation d'un élément
Pour récuperer un livre, vous devez tout d'abord récupérer l'auteur par son id, puis trouver le livre en utilisant son nom.
app.get('/authors/:id/books/:name', async (req, res) => {
// Récuperer les paramètres id et bookID
const { id, bookID } = req.params;
try {
// Récuperer l'auteur avec son ID
const author = await Author.findById(id);
// Si l'auteur n'existe pas, retourner 404
if (!author) return res.status(404).json({ message: "Auteur introuvable" });
// Récuperer le livre avec son ID
const book = author.books.id(bookID);
// Si le livre n'existe pas, retourner 404
if (!book) return res.status(404).json({ message: "Book introuvable" });
// Si tout va bien, retourner le livre avec status 200
res.status(200).json({ book });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
3. Mise à jour d'un élément
Pour mettre à jour un livre, vous devez tout d'abord récupérer l'auteur par son id, puis trouver le livre en utilisant son id, dans notre cas réçue dans les paramètre de la reqûete.
Puis utiliser la méthodes
app.get('/authors/:id/books/:bookID', async (req, res) => {
// Récuperer les paramètres id et bookID
const { id, bookID } = req.params;
try {
// Récuperer l'auteur avec son ID
const author = await Author.findById(id);
// Si l'auteur n'existe pas, retourner 404
if (!author) return res.status(404).json({ message: "Auteur introuvable" });
// Récuperer le livre avec son ID
let book = author.books.id(bookID);
// Si le livre n'existe pas, retourner 404
if (!book) return res.status(404).json({ message: "Book introuvable" });
// Mettre à jour le livre
book.set(req.body);
// Mettre à jour l'auetur dans la BDD
await author.save();
// Si tout va bien, retourner le livre avec status 200
res.status(200).json({ author });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
S. Supprimer un élément
Pour supprimer un livre, vous devez tout d'abord récupérer l'auteur par son id, puis trouver le livre en utilisant son id, dans notre cas réçue dans les paramètre de la reqûete.
Puis utiliser la méthode pull sur le tableau books en envoyant le livre book récuperer en paramètre.
Puis nous enregistrant l'auteur pour le mettre à jour dans la Base de données.
app.get('/authors/:id/books/:bookID', async (req, res) => {
// Récuperer les paramètres id et bookID
const { id, bookID } = req.params;
try {
// Récuperer l'auteur avec son ID
const author = await Author.findById(id);
// Si l'auteur n'existe pas, retourner 404
if (!author) return res.status(404).json({ message: "Auteur introuvable" });
// Récuperer le livre avec son ID
let book = author.books.id(bookID);
// Si le livre n'existe pas, retourner 404
if (!book) return res.status(404).json({ message: "Book introuvable" });
// supprimer le livre
author.books.pull(book);
// Mettre à jour l'auetur dans la BDD
await author.save();
// Si tout va bien, retourner le livre avec status 200
res.status(200).json({ author });
} catch (error) {
res.status(500).json({ message: "Erreur serveur" });
}
});
Conclusion
En conclusion, nous avons vu comment utiliser Mongoose et ExpressJS pour créer des modèles et effectuer des opérations CRUD sur une base de données MongoDB.
Nous avons commencé par comprendre la définition des schémas et modèles, et comment les utiliser dans les routes ExpressJS pour créer, lire, mettre à jour et supprimer des données.
Ensuite, nous avons exploré les différentes méthodes pour effectuer une recherche de données, que ce soit avec des critères simples ou complexes.
Nous avons également appris à mettre en place une pagination des données pour améliorer les performances de notre application.
Le prochain chapitre portera sur les relations entre modèles dans Mongoose.
Dans la création d'applications, il est courant de devoir manipuler des données qui ont des liens entre elles.
Les relations permettent de définir comment les données sont associées et de créer des requêtes pour récupérer les données liées.
Nous verrons les différents types de relations entre modèles et comment les définir avec Mongoose.
Nous explorerons également comment utiliser ces relations dans les routes ExpressJS.
Aller plus loin

Express.js + Mongoose.js
Un cours complèt qui vous permettra de maîtriser l'utilisation de Mongoose avec ExpressJS pour la gestion de bases de données MongoDB dans vos projets de développement web.
Javascript
NodeJS
ExpressJS
Serveurs
HTTP
Back-End
Mongoose
MongoDB