<-

Retour

2. Express + Mongoose: Les Opérations

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.

0

Partager sur twitterPartager sur FacebookPartager sur LinkdinPartager sur Telegram

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:


  1. Initiation au language Javascript.

  1. Initiation à la programmation serveur avec NodeJS.

Il faut aussi avoir des connaissances dans la création d'application avec Express.js:


  1. Initiation à la librairie Express.js.


Objectifs

À la fin de ce chapitre, vous serez en mesure de :


  1. Créer des modèles Mongoose
  2. Définir des schémas de validation
  3. Réaliser des opérations CRUD avec Mongoose et ExpressJS
  4. Gérer les relations entre les modèles
  5. 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:


  1. "name": Champs de type chaine de caratcère, obligatoire et unique dans la collection
  2. "age": Champs de type nombre et obligatoire
  3. "alive": Champ de type boolean, obligatoire, faux par défaut
  4. "adress": Objet avec deux champs:
    1. country: Champ de type chaine de caractère obligatoire
    2. city: Champ de type chaine de caractères non obligatoire
  5. books: Champs de type liste/tableau d'objets:
    1. title: Champs de type chaine de caractères, obligatoire
    2. date: Champs de type chaine de caractères
    3. 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