Fondamentaux, requêtes avancées et agrégation

Se connecter pour s'inscrire

Votre progression

Continuez pour débloquer la suite !
0 / 0 étapes complétées 0
%

Syllabus

  1. Description

  2. Objectifs

  3. Validations de compétences

  4. Public cible

    Aucun public cible spécifié pour ce module.

  5. Besoins techniques

  6. Prérequis

    • Aucun prérequis
  7. Niveau

  8. Historique du module

    Aucune action enregistrée

Fondamentaux, requêtes avancées et agrégation

  1. Les Fondamentaux de MongoDB

    1. Introduction à MongoDB et aux bases NoSQL

      1. Qu'est-ce que MongoDB ?

        MongoDB est une base de données NoSQL orientée document, conçue pour la flexibilité, la scalabilité horizontale et les performances élevées.

        graph TD %% Niveaux principaux A[MongoDB] --> B[Base de données] B --> C[Collection] C --> D[Document] %% Documents dans la collection C --> Doc1[Document 1] C --> Doc2[Document 2] C --> Doc3[Document ...] %% Structure d'un document Doc1 --> Field1[_id: ObjectId] Doc1 --> Field2[nom] Doc1 --> Field3[email] Doc1 --> Field4[adresse] %% Styles de base style A fill:#4db8ff,stroke:#4db8ff,color:white style B fill:#4db8ff,stroke:#4db8ff,color:white style C fill:#ff6b6b,stroke:#ff6b6b,color:white style Doc1 fill:#6c5ce7,stroke:#6c5ce7,color:white,stroke-dasharray: 5 5 style Doc2 fill:#6c5ce7,stroke:#6c5ce7,color:white,stroke-dasharray: 5 5 style Doc3 fill:#6c5ce7,stroke:#6c5ce7,color:white,stroke-dasharray: 5 5
        Les collections MongoDB

        Une collection dans MongoDB est un groupe de documents, équivalent à une table dans les bases de données relationnelles. Cependant, contrairement aux tables, les collections n'imposent pas de schéma strict.

        Caractéristiques des collections :

        • Pas de schéma imposé : les documents d'une même collection peuvent avoir des structures différentes
        • Haute performance : optimisées pour les opérations de lecture/écriture
        • Indexables : permet des recherches rapides
        Bon à savoir : Par convention, les noms de collections sont au pluriel (ex: users, orders).

        Figure 1 : Architecture de MongoDB montrant les relations entre les différents composants.

      2. Pourquoi choisir MongoDB ?

        1. Performance

          Moteur de stockage haute performance avec :

          Exemple de performance

          Un site e-commerce utilisant MongoDB peut gérer jusqu'à 100 000 lectures par seconde avec des temps de réponse inférieurs à 10ms, ce qui permet une expérience utilisateur fluide même pendant les périodes de pointe comme le Black Friday.

          • Support natif de la réplication
          • Sharding intégré
          • Indexation avancée
          • Cache de requêtes
        2. Scalabilité

          Architecture distribuée conçue pour :

          Exemple de scalabilité

          Une application de médias sociaux peut commencer avec un seul serveur MongoDB. À mesure que le nombre d'utilisateurs passe de 1 000 à 10 millions, l'application peut évoluer en ajoutant des shards (partitions de données) sur plusieurs serveurs, sans temps d'arrêt.

          • Échelle horizontale facile
          • Répartition des charges
          • Haute disponibilité
        3. Modèle de données flexible

          Avantages du schéma dynamique :

          Exemple de flexibilité

          Dans une application de blog, vous pourriez initialement stocker uniquement le titre et le contenu d'un article. Plus tard, vous pourriez ajouter des champs comme des tags, une image de couverture ou des commentaires directement dans le même document, sans avoir à modifier la structure de la base de données.

          ```
          // Premier enregistrement
          {
            titre: "Mon premier article",
            contenu: "Contenu de l'article...",
            date: ISODate("2023-01-01")
          }
          
          // Plus tard, ajout de nouveaux champs sans modification de schéma
          {
            titre: "Nouvel article",
            contenu: "Contenu mis à jour...",
            date: ISODate("2023-04-15"),
            tags: ["technologie", "programmation"],
            image: "url-de-l-image.jpg",
            auteur: {
              nom: "Alice",
              role: "rédacteur"
            },
            commentaires: [
              { auteur: "Bob", texte: "Super article !", date: ISODate("2023-04-16") }
            ]
          }
          ```
          
          • Évolution sans temps d'arrêt
          • Documents hétérogènes
          • Modélisation naturelle des données
        4. Écosystème riche

          Une large gamme d'outils :

          Exemples d'outils populaires

          • MongoDB Compass : Interface graphique pour explorer et manipuler les données
          • MongoDB Atlas : Service cloud géré avec hébergement sur AWS, Azure ou GCP
          • MongoDB Charts : Outil de visualisation de données intégré
          • MongoDB BI Connector : Permet d'utiliser des outils BI comme Tableau avec MongoDB
          • Drivers officiels : Pour Node.js, Python, Java, C#, etc.

          Astuce : Ces outils rendent MongoDB accessible aussi bien aux développeurs qu'aux analystes de données, facilitant ainsi la collaboration entre les équipes.

          • Drivers pour tous les langages majeurs
          • Outils de gestion (Compass, Atlas)
          • Intégrations cloud
          • Communauté active
      3. Concepts clés du NoSQL

        1. Modèles de données NoSQL

          • Document

            Stockage de documents JSON/BSON

            Ex: MongoDB, CouchDB

          • Clé-Valeur

            Stockage simple clé-valeur

            Ex: Redis, DynamoDB

          • Colonnes larges

            Stockage par colonnes

            Ex: Cassandra, HBase

          • Graphes

            Relations complexes entre données

            Ex: Neo4j, ArangoDB

        2. ACID vs BASE

          ACID (SQL) BASE (NoSQL) Description
          Atomicité Disponibilité de base Disponibilité même en cas de pannes
          Cohérence État souple (Soft state) Les données peuvent évoluer sans mise à jour
          Isolation Cohérence à terme Les données finissent par être cohérentes
          Durabilité Scalabilité horizontale Capacité à gérer de grandes quantités de données
      4. Quand utiliser MongoDB ?

        Idéal pour
        • Applications web et mobiles API RESTful
        • Gestion de contenu (CMS) Contenu dynamique
        • Catalogues produits E-commerce
        • Données IoT et séries temporelles Big Data
        • Profils utilisateurs Données utilisateurs
        • Données géospatiales Géolocalisation
        Moins adapté pour
        • Applications financières Transactions complexes
        • Systèmes relationnels Jointures complexes
        • Applications critiques Cohérence forte requise
        • Requêtes complexes SQL avancé
        • Données hautement relationnelles Modèle relationnel
        Conseil :

        MongoDB excelle dans les cas d'utilisation nécessitant flexibilité et évolutivité. Pour les systèmes transactionnels complexes, envisagez une base de données relationnelle traditionnelle.

      5. Opérations CRUD avec MongoDB

        Les opérations CRUD (Create, Read, Update, Delete) sont fondamentales pour interagir avec une base de données MongoDB. Voici comment les mettre en œuvre :

        1. Create - Insertion de documents

          Pour insérer des documents dans une collection :

                              // Insérer un seul document
                                db.collection('users').insertOne({
                                  name: 'Jean Dupont',
                                  email: 'jean@exemple.com',
                                  age: 30,
                                  status: 'actif'
                                });
          
                                // Insérer plusieurs documents
                                db.collection('posts').insertMany([
                                  { title: 'Premier article', content: 'Contenu...', likes: 0 },
                                  { title: 'Deuxième article', content: 'Contenu...', tags: ['tech', 'mongodb'] }
                                ]);
                              
                            
          MongoDB génère automatiquement un _id unique pour chaque document si aucun n'est spécifié.
        2. Read - Lecture de documents

          Pour rechercher des documents :

                              // Trouver tous les documents
                                  db.collection('users').find({});
          
                                  // Avec des critères de recherche
                                  db.collection('users').find({ status: 'actif' });
          
                                  // Avec projection (sélection des champs)
                                  db.collection('users').find(
                                    { age: { $gt: 25 } },
                                    { projection: { name: 1, email: 1, _id: 0 } }
                                  );
          
                                  // Trier et limiter les résultats
                                  db.collection('posts')
                                    .find({})
                                    .sort({ created_at: -1 })
                                    .limit(10);
                                
                            
        3. Update - Mise à jour de documents

          Pour mettre à jour des documents :

                              // Mettre à jour un seul document
                                db.collection('users').updateOne(
                                  { email: 'jean@exemple.com' },
                                  { $set: { status: 'inactif' } }
                                );
          
                                // Mettre à jour plusieurs documents
                                db.collection('posts').updateMany(
                                  { views: { $lt: 100 } },
                                  { $inc: { views: 1 } }
                                );
          
                                // Opérateurs de mise à jour courants :
                                // $set, $unset, $inc, $push, $pull, $addToSet
                              
                            
        4. Delete - Suppression de documents

          Pour supprimer des documents :

                              // Supprimer un seul document
                                db.collection('users').deleteOne({ email: 'jean@exemple.com' });
          
                                // Supprimer plusieurs documents
                                db.collection('posts').deleteMany({ status: 'archived' });
          
                                // Attention : Sans filtre, cela supprime tous les documents de la collection !
                                // db.collection('users').deleteMany({});
                              
                            
          Attention : Les opérations de suppression sont irréversibles. Toujours vérifier ses critères de sélection avant de supprimer.
        5. Bonnes pratiques CRUD

          • Utilisez des index pour optimiser les requêtes de lecture
          • Privilégiez les opérations en masse (insertMany, updateMany) pour améliorer les performances
          • Utilisez les transactions pour les opérations atomiques sur plusieurs documents
          • Limitez les champs retournés avec la projection pour réduire la charge réseau
          • Pensez à la cohérence des données dans un environnement distribué
    2. Structure des documents MongoDB

      1. Introduction au format BSON

        MongoDB utilise le format BSON (Binary JSON) pour stocker les documents. C'est une représentation binaire de JSON avec des types de données supplémentaires.

        Avantages du BSON :

        1. Plus rapide à analyser que JSON
        2. Supporte plus de types de données
        3. Efficace pour le stockage et la récupération
      2. Anatomie d'un document

        Un document MongoDB typique :

        {
          _id: ObjectId("507f1f77bcf86cd799439011"),
          nom: "Jean Dupont",
          age: 30,
          email: "jean.dupont@example.com",
          adresse: {
            rue: "123 Rue Exemple",
            ville: "Paris",
            codePostal: "75000"
          },
          competences: ["MongoDB", "JavaScript", "Node.js"],
          dateInscription: ISODate("2023-01-15T10:30:00Z")
        }
      3. Types de données

        1. Types scalaires
          1. String : Chaînes de caractères UTF-8
          2. Number : Entiers, décimaux, doubles
          3. Boolean : true/false
          4. Date : Horodatage
          5. Null : Valeur nulle
        2. Types composés
          1. Document : Objet imbriqué
          2. Array : Tableau de valeurs
        3. Types spéciaux
          1. ObjectId : Identifiant unique
          2. Binary Data : Données binaires
          3. Regular Expression : Expressions régulières
          4. Timestamp : Horodatage interne
      4. Bonnes pratiques de modélisation

        1. Conception orientée documents

          Regrouper les données fréquemment accédées ensemble

        2. Éviter les jointures excessives

          Privilégier l'imbrication quand c'est pertinent

        3. Utilisation des références

          Pour les relations un-à-plusieurs ou plusieurs-à-plusieurs

        4. Considérations sur la taille des documents

          Éviter les documents trop volumineux (>16Mo)

    3. Guide Complet des Opérations MongoDB

      Ce guide couvre en détail les opérations CRUD (Create, Read, Update, Delete) dans MongoDB.

      Recherche de Documents (find)

      1. Syntaxe de Base

            
                // Syntaxe de base de la méthode find()
                // db.collection.find(query, projection)
        
                // Exemple 1: Trouver tous les documents
                const allDocuments = db.users.find({});
        
                // Exemple 2: Trouver avec des critères de recherche
                const activeUsers = db.users.find({
                    status: 'active',
                    lastLogin: { $gt: new Date('2023-01-01') }
                });
        
                // Exemple 3: Utilisation de la projection
                const userNames = db.users.find(
                    { role: 'user' },
                    { 
                        name: 1, 
                        email: 1,
                        _id: 0  // Exclure le champ _id
                    }
                );
        
                // Exemple 4: Trier et limiter les résultats
                const recentOrders = db.orders
                    .find({ status: 'completed' })
                    .sort({ orderDate: -1 })
                    .limit(10);
        
                // Exemple 5: Compter les documents
                const activeUserCount = db.users.countDocuments({ status: 'active' });
        
                // Exemple 6: Utilisation d'opérateurs de requête
                const highValueOrders = db.orders.find({
                    total: { $gt: 1000 },  // Montant supérieur à 1000
                    status: { $in: ['pending', 'processing'] },  // Statut dans la liste
                    orderDate: { 
                        $gte: new Date('2023-01-01'),
                        $lt: new Date('2024-01-01')
                    }
                });
        
                // Exemple 7: Recherche avec expression régulière
                const nameStartsWithJ = db.users.find({
                    name: { $regex: /^J/i }  // Noms commençant par J (insensible à la casse)
                });
        
                // Exemple 8: Requête sur des tableaux
                const usersWithSpecificTags = db.users.find({
                    tags: { $all: ['premium', 'verified'] }  // Doit avoir tous les tags spécifiés
                });
        
                // Exemple 9: Requête avec opérateurs logiques
                const complexQuery = db.products.find({
                    $or: [
                        { category: 'electronics', price: { $lt: 500 } },
                        { category: 'books', rating: { $gte: 4 } }
                    ],
                    inStock: true
                });
        
                // Exemple 10: Utilisation de $elemMatch pour les tableaux d'objets
                const usersWithSpecificAddress = db.users.find({
                    addresses: {
                        $elemMatch: {
                            type: 'billing',
                            city: 'Paris'
                        }
                    }
                });
            
        
      2. Exemple Simple

            
              // Trouver tous les utilisateurs actifs
              db.users.find({ 
                  status: 'active',
                  lastLogin: { $gt: new Date('2023-01-01') }
              }).sort({ createdAt: -1 });
            
        
      3. Avec Projection

            
                // Sélectionner uniquement certains champs
                db.users.find(
                { role: 'customer' },
                { 
                    name: 1, 
                    email: 1, 
                    _id: 0  // Exclure le champ _id
                }
                ).limit(10);
            
        
      4. Opérateurs de Requête Courants

        Opérateur Description Exemple
        $eq Égal à { age: { $eq: 25 } }
        $gt, $gte Plus grand (ou égal) que { age: { $gt: 21 } }
        $in, $nin Dans / pas dans un tableau { role: { $in: ["admin", "editor"] } }
        $and, $or Opérateurs logiques { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] }
      5. Bonnes Pratiques

        • Utilisez des index pour améliorer les performances
        • Limitez les champs retournés avec la projection
        • Évitez les opérations qui scannent toute la collection (COLLSCAN)
        • Utilisez .explain() pour analyser les performances des requêtes
      1. Les Commandes d'Insertion

        1. Méthodes Disponibles

          1. insertOne()

            Insère un seul document
            // Insérer un seul document
            const result = await db.users.insertOne({
              name: "Jean Dupont",
              email: "jean@example.com",
              age: 30,
              roles: ["user", "admin"],
              createdAt: new Date()
            });
            
            console.log(`Document inséré avec l'ID: ${result.insertedId}`);
            
            // Résultat attendu :
            // Document inséré avec l'ID: 5f8d... (ObjectId)
          2. insertMany()

            Insère plusieurs documents
            // Insérer plusieurs documents
            const result = await db.products.insertMany([
              {
                name: "Ordinateur portable",
                category: "Électronique",
                price: 999.99,
                inStock: true,
                tags: ["nouveau", "promo"]
              },
              {
                name: "Souris sans fil",
                category: "Périphériques",
                price: 49.99,
                inStock: true
              },
              {
                name: "Clavier mécanique",
                category: "Périphériques",
                price: 89.99,
                inStock: false
              }
            ], {
              writeConcern: { w: "majority" },
              ordered: true  // Annule l'insertion en cas d'erreur
            });
            
            console.log(`${result.insertedCount} documents insérés`);
            console.log("IDs des documents insérés:", result.insertedIds);
            
            // Résultat attendu :
            // 3 documents insérés
            // IDs des documents insérés: {
            //   '0': ObjectId("..."),
            //   '1': ObjectId("..."),
            //   '2': ObjectId("...")
            // }
        2. Options d'Insertion

          Option Type Description Valeur par défaut
          writeConcern Document Niveau de garantie d'écriture { w: 1 }
          ordered Boolean Arrêter à la première erreur si false true
          bypassDocumentValidation Boolean Contourner la validation du schéma false
        3. Bonnes Pratiques

          • Utilisez insertMany() pour insérer plusieurs documents en une seule opération
          • Désactivez ordered pour ignorer les erreurs et continuer l'insertion
          • Validez les données avant l'insertion
          • Utilisez des transactions pour des opérations atomiques sur plusieurs collections
        4. Génération des _id

          Si non spécifié, MongoDB génère un _id unique de type ObjectId :

                              
                                {
                                    _id: ObjectId("507f1f77bcf86cd799439011"),  // Format 12-byte
                                    // 4 bytes: timestamp
                                    // 5 bytes: random value
                                    // 3 bytes: counter
                                    ...
                                  }
                                
                            

          Pour utiliser un identifiant personnalisé :

          // Insérer un seul document
          const result = await db.users.insertOne({
            name: "Jean Dupont",
            email: "jean@example.com",
            age: 30,
            roles: ["user", "admin"],
            createdAt: new Date()
          });
          
          console.log(`Document inséré avec l'ID: ${result.insertedId}`);
          
          // Résultat attendu :
          // Document inséré avec l'ID: 5f8d... (ObjectId)
      2. Les Commandes de Mise à Jour

        1. Méthodes Principales

          1. updateOne()

            Met à jour un seul document
            // Mettre à jour un document spécifique
            const result = await db.products.updateOne(
              { _id: ObjectId("507f1f77bcf86cd799439011") },  // Filtre
              {
                $set: {  // Opérateur de mise à jour
                  price: 1099.99,
                  lastModified: new Date()
                },
                $inc: { viewCount: 1 },
                $addToSet: { tags: "nouveau" }
              },
              {
                upsert: false,  // Ne pas créer le document s'il n'existe pas
                writeConcern: { w: "majority" }
              }
            );
            
            console.log(`${result.matchedCount} document(s) correspondant(s)`);
            console.log(`${result.modifiedCount} document(s) modifié(s)`);
            console.log(`ID du document inséré: ${result.upsertedId || 'Aucun'}`);
            
            // Résultat attendu :
            // 1 document(s) correspondant(s)
            // 1 document(s) modifié(s)
            // ID du document inséré: Aucun
          2. updateMany()

            Met à jour plusieurs documents
            // Mettre à jour plusieurs documents correspondant aux critères
            const result = await db.products.updateMany(
              { 
                category: "Électronique",
                price: { $lt: 1000 }  // Produits électroniques à moins de 1000€
              },
              {
                $set: { 
                  onSale: true,
                  discount: 0.1,  // 10% de réduction
                  lastPromoUpdate: new Date()
                },
                $inc: { price: 50 }  // Augmenter le prix de 50€
              },
              {
                writeConcern: { w: "majority" },
                upsert: false
              }
            );
            
            console.log(`${result.matchedCount} document(s) correspondant(s)`);
            console.log(`${result.modifiedCount} document(s) modifié(s)`);
            console.log(`ID du document inséré: ${result.upsertedId || 'Aucun'}`);
            
            // Résultat attendu (exemple) :
            // 15 document(s) correspondant(s)
            // 15 document(s) modifié(s)
            // ID du document inséré: Aucun
        2. Opérateurs de Mise à Jour

          1. Opérateurs de Champs

            • $set : Définit la valeur d'un champ
            • $unset : Supprime un champ
            • $rename : Renomme un champ
            • $inc : Incrémente une valeur numérique
            • $mul : Multiplie une valeur numérique
            • $min/$max : Met à jour si la valeur est plus petite/plus grande
          2. Opérateurs de Tableaux

            • $push : Ajoute un élément à un tableau
            • $addToSet : Ajoute si non présent
            • $pop : Supprime le premier/dernier élément
            • $pull : Supprime les éléments correspondants
            • $pullAll : Supprime plusieurs valeurs
            • $each : Utilisé avec $push et $addToSet pour ajouter plusieurs éléments
          3. Exemple Complet avec Opérateurs

                                                // Mettre à jour un profil utilisateur complexe
                                                    await db.users.updateOne(
                                                        { _id: userId },
                                                        {
                                                        $set: {
                                                            "profile.lastUpdated": new Date(),
                                                            "contact.email": "new.email@example.com",
                                                            "settings.theme": "dark"
                                                        },
                                                        $inc: { "stats.profileViews": 1 },
                                                        $addToSet: { 
                                                            tags: { $each: ["premium", "verified"] } 
                                                        },
                                                        $pull: { 
                                                            notifications: { 
                                                            type: "promo",
                                                            status: "unread" 
                                                            } 
                                                        }
                                                        },
                                                        { 
                                                        upsert: true,  // Crée le document s'il n'existe pas
                                                        writeConcern: { w: "majority" }
                                                        }
                                                    );
                                                
                                            
        3. Pièges Courants

          • Les mises à jour atomiques ne sont pas garanties sans _id dans le filtre
          • Les opérations de mise à jour sont atomiques au niveau du document
          • Les index peuvent affecter les performances des mises à jour
          • Les validations de schéma s'appliquent aux mises à jour
        4. Mise à Jour avec Agrégation (MongoDB 4.2+)

          Permet des mises à jour complexes en utilisant le pipeline d'agrégation :

                                      // Mettre à jour en fonction des valeurs existantes
                                          await db.orders.updateMany
                                          (
                                              { status: "processing" },
                                              [
                                              {
                                                  $set: {
                                                  lastUpdated: "$$NOW",
                                                  total: {
                                                      $add: [
                                                      "$subtotal",
                                                      { $multiply: ["$subtotal", "$taxRate"] },
                                                      "$shipping"
                                                      ]
                                                  }
                                                  }
                                              },
                                              {
                                                  $unset: ["tempField1", "tempField2"]
                                              }
                                          ]
                                          );
                                      
                                  
      3. Suppression de Documents

        Attention : Les opérations de suppression sont irréversibles. Utilisez ces commandes avec précaution.
        1. deleteOne()

          Suppression d'un document
          // Supprimer un document spécifique
          const result = await db.users.deleteOne(
            { _id: ObjectId("507f1f77bcf86cd799439011") },  // Filtre
            {
              writeConcern: { w: "majority" },
              collation: { locale: "fr", strength: 1 }  // Optionnel : pour la sensibilité à la casse
            }
          );
          
          console.log(`${result.deletedCount} document(s) supprimé(s)`);
          
          // Exemple avec journalisation avant suppression
          try {
            const user = await db.users.findOne({ _id: ObjectId("507f1f77bcf86cd799439011") });
            if (user) {
              await db.deletedUsers.insertOne({
                ...user,
                deletedAt: new Date(),
                deletedBy: "admin@example.com"
              });
              
              const result = await db.users.deleteOne({ _id: user._id });
              console.log(`Utilisateur ${user.email} supprimé avec succès`);
            }
          } catch (error) {
            console.error("Erreur lors de la suppression:", error);
          }
          
          // Résultat attendu (exemple) :
          // 1 document(s) supprimé(s)
          // OU
          // Utilisateur test@example.com supprimé avec succès
        2. deleteMany()

          Suppression de plusieurs documents
          // Supprimer plusieurs documents correspondant aux critères
          const result = await db.logs.deleteMany(
            { 
              // Supprimer les logs plus anciens que 30 jours
              timestamp: { 
                $lt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000)
              },
              // Ne pas supprimer les logs importants
              priority: { $ne: "high" }
            },
            {
              writeConcern: { 
                w: "majority",
                wtimeout: 5000  // Timeout de 5 secondes
              },
              comment: "Nettoyage des logs mensuel"  // Pour le suivi des opérations
            }
          );
          
          console.log(`${result.deletedCount} logs supprimés`);
          
          // Exemple avec journalisation avancée
          const batchSize = 1000;
          let deletedCount = 0;
          let lastId = null;
          
          while (true) {
            // Récupérer un lot de documents à supprimer
            const batch = await db.logs
              .find(lastId ? { 
                _id: { $gt: lastId },
                timestamp: { $lt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
              } : { 
                timestamp: { $lt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
              })
              .sort({ _id: 1 })
              .limit(batchSize)
              .toArray();
          
            if (batch.length === 0) break;
            
            // Récupérer les IDs à supprimer
            const idsToDelete = batch.map(doc => doc._id);
            
            // Journaliser avant suppression
            await db.deletedLogs.insertMany(batch.map(doc => ({
              ...doc,
              deletedAt: new Date(),
              deletedBy: "cleanup-script"
            })));
            
            // Supprimer le lot
            const result = await db.logs.deleteMany({ _id: { $in: idsToDelete } });
            deletedCount += result.deletedCount;
            
            // Mettre à jour le dernier ID traité
            lastId = batch[batch.length - 1]._id;
            
            console.log(`Lot de ${result.deletedCount} logs supprimés (total: ${deletedCount})`);
            
            // Pause pour réduire la charge sur le serveur
            await new Promise(resolve => setTimeout(resolve, 100));
          }
          
          console.log(`Opération terminée. Total supprimé: ${deletedCount} logs.`);
          
          // Résultat attendu (exemple) :
          // Lot de 1000 logs supprimés (total: 1000)
          // Lot de 1000 logs supprimés (total: 2000)
          // Lot de 345 logs supprimés (total: 2345)
          // Opération terminée. Total supprimé: 2345 logs.
        3. Bonnes Pratiques

          • Toujours sauvegarder les données avant des suppressions en masse
          • Utiliser des transactions pour des suppressions atomiques sur plusieurs collections
          • Envisagez d'utiliser des "suppressions logiques" (champ "deleted") plutôt que des suppressions physiques
          • Testez toujours les critères de suppression avec une requête find() d'abord
      4. Requêtes Avancées MongoDB

        Cette section couvre des requêtes complexes combinant plusieurs opérateurs et étapes d'agrégation.
        1. Jointures Complexes avec $lookup et $unwind

          Scénario :

          Récupérer les commandes avec les détails des produits et les informations clients, en calculant le total par catégorie.

              
                  db.orders.aggregate([
            // Étape 1: Filtrer les commandes des 30 derniers jours
            {
              $match: {
                orderDate: { $gte: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
              }
            },
            
            // Étape 2: Joindre avec la collection des clients
            {
              $lookup: {
                from: "customers",
                localField: "customerId",
                foreignField: "_id",
                as: "customer"
              }
            },
            
            // Étape 3: Déplier le tableau des articles commandés
            { $unwind: "$items" },
            
            // Étape 4: Joindre avec la collection des produits
            {
              $lookup: {
                from: "products",
                localField: "items.productId",
                foreignField: "_id",
                as: "product"
              }
            },
            
            // Étape 5: Déplier le tableau des produits
            { $unwind: "$product" },
            
            // Étape 6: Calculer le total pour chaque ligne de commande
            {
              $addFields: {
                "items.total": { $multiply: ["$items.quantity", "$product.price"] }
              }
            },
            
            // Étape 7: Grouper par catégorie de produit et calculer les totaux
            {
              $group: {
                _id: { category: "$product.category" },
                totalSales: { $sum: "$items.total" },
                orderCount: { $sum: 1 },
                averageOrderValue: { $avg: "$items.total" }
              }
            },
            
            // Étape 8: Trier par total des ventes (décroissant)
            { $sort: { totalSales: -1 } }
          ])
              
          

          Explication :

          1. $match : Filtre les commandes récentes
          2. $lookup : Jointure avec la collection des clients
          3. $unwind : Déploie le tableau des articles
          4. $lookup : Jointure avec la collection des produits
          5. $group : Agrège par catégorie avec calculs
          6. $project : Formate le résultat final
        2. Requêtes Géospatiales Avancées

          Scénario :

          Trouver les 10 restaurants les plus proches dans un rayon de 2 km, avec une note moyenne supérieure à 4.

          Recherche géospatiale avec agrégation
          // 1. Création d'un index géospatial 2dsphere (à exécuter une seule fois)
          // db.restaurants.createIndex({ location: "2dsphere" });
          
          // 2. Requête pour trouver les restaurants à proximité
          const pointInteret = {
            type: "Point",
            coordinates: [2.3522, 48.8566]  // Paris, France
          };
          
          const result = await db.restaurants.aggregate([
            {
              $geoNear: {
                near: pointInteret,
                distanceField: "distance",
                maxDistance: 2000,  // 2 km en mètres
                spherical: true,
                query: { 
                  'grades.score': { $gte: 4 },
                  cuisine: { $exists: true }
                }
              }
            },
            {
              $lookup: {
                from: "neighborhoods",
                localField: "neighborhood",
                foreignField: "name",
                as: "neighborhood_info"
              }
            },
            { $unwind: "$neighborhood_info" },
            {
              $project: {
                name: 1,
                cuisine: 1,
                "address.street": 1,
                distance: { $round: ["$distance", 0] },
                neighborhood: "$neighborhood_info.name",
                borough: 1,
                lastGrade: { $arrayElemAt: ["$grades", -1] }
              }
            },
            { $sort: { distance: 1 } },
            { $limit: 10 }
          ]);
          
          console.log(JSON.stringify(result, null, 2));
        3. Recherche de Texte Avancée

          Scénario :

          Recherche avancée d'articles de blog avec pondération des champs, filtrage par date, catégorie et popularité.

          Recherche de texte avancée avec agrégation
          // 1. Création d'un index de recherche en texte (à exécuter une seule fois)
          // db.articles.createIndex(
          //   { 
          //     title: "text", 
          //     content: "text",
          //     tags: "text"
          //   },
          //   {
          //     weights: {
          //       title: 5,    // Le titre a plus de poids
          //       tags: 3,     // Les tags ont un poids moyen
          //       content: 1   // Le contenu a le poids le plus faible
          //     },
          //     name: "text_search_index"
          //   }
          // );
          
          // 2. Requête de recherche avancée avec agrégation
          const searchTerm = "développement web";
          const minDate = new Date(new Date().setFullYear(new Date().getFullYear() - 1)); // Dernière année
          
          const result = await db.articles.aggregate([
            {
              $search: {
                text: {
                  query: searchTerm,
                  path: ["title", "content", "tags"],
                  fuzzy: {
                    maxEdits: 2,        // Tolère jusqu'à 2 fautes de frappe
                    prefixLength: 3,    // Nécessite les 3 premières lettres exactes
                    maxExpansions: 100  // Limite l'expansion des termes
                  },
                  score: { 
                    // Boost pour les correspondances exactes
                    boost: { value: 2 }
                  }
                },
                // Filtres supplémentaires
                compound: {
                  filter: [
                    { 
                      range: {
                        path: "publishedAt",
                        gte: minDate,
                        lte: new Date()
                      }
                    },
                    { 
                      range: {
                        path: "readTime",
                        lte: 15  // Temps de lecture max de 15 minutes
                      }
                    },
                    { 
                      text: {
                        query: ["tutoriel", "guide", "exemple"],
                        path: "tags"
                      }
                    }
                  ],
                  // Boost pour les articles populaires
                  should: [
                    {
                      range: {
                        path: "views",
                        boost: {
                          linear: {
                            origin: 0,
                            scale: 10000,
                            decay: 0.5
                          }
                        }
                      }
                    },
                    {
                      range: {
                        path: "claps",
                        boost: {
                          linear: {
                            origin: 0,
                            scale: 1000,
                            decay: 0.5
                          }
                        }
                      }
                    }
                  ]
                }
              }
            },
            // Jointure avec la collection des auteurs
            {
              $lookup: {
                from: "users",
                localField: "authorId",
                foreignField: "_id",
                as: "author"
              }
            },
            { $unwind: "$author" },
            // Projection des champs pertinents
            {
              $project: {
                _id: 1,
                title: 1,
                excerpt: 1,
                readTime: 1,
                publishedAt: 1,
                views: 1,
                claps: 1,
                tags: 1,
                author: {
                  name: 1,
                  avatar: 1,
                  title: 1
                },
                // Calcul du score de pertinence
                relevance: {
                  $meta: "searchScore"
                },
                // Calcul d'un score personnalisé
                score: {
                  $add: [
                    { $multiply: [{ $meta: "searchScore" }, 0.6] },
                    { $multiply: [{ $divide: ["$views", 1000] }, 0.2] },
                    { $multiply: [{ $divide: ["$claps", 100] }, 0.2] }
                  ]
                }
              }
            },
            // Tri par score personnalisé
            { $sort: { score: -1 } },
            // Pagination
            { $skip: 0 },
            { $limit: 10 }
          ]);
          
          console.log(JSON.stringify(result, null, 2));
        4. Agrégations Temporelles

          Scénario :

          Analyser les ventes par période (jour, semaine, mois) avec des fenêtres glissantes.

          Agrégation de séries temporelles avancée
          // 1. Création d'une collection de séries temporelles (à exécuter une seule fois)
          // db.createCollection("sensorReadings", {
          //   timeseries: {
          //     timeField: "timestamp",
          //     metaField: "sensorId",
          //     granularity: "minutes"
          //   }
          // });
          
          // 2. Agrégation avancée sur les séries temporelles
          const startDate = new Date();
          startDate.setMonth(startDate.getMonth() - 6); // Données des 6 derniers mois
          
          const result = await db.sensorReadings.aggregate([
            // Étape 1: Filtrer par plage de dates
            {
              $match: {
                timestamp: { $gte: startDate },
                status: "active"
              }
            },
            
            // Étape 2: Grouper par fenêtres de temps et capteur
            {
              $group: {
                _id: {
                  // Arrondir à l'heure la plus proche
                  date: {
                    $dateTrunc: {
                      date: "$timestamp",
                      unit: "hour",
                      binSize: 1
                    }
                  },
                  sensorId: "$sensorId",
                  location: "$location"
                },
                // Calculer les métriques
                avgValue: { $avg: "$value" },
                maxValue: { $max: "$value" },
                minValue: { $min: "$value" },
                sampleCount: { $sum: 1 },
                // Détecter les anomalies (valeurs en dehors de 2 écarts-types)
                stdDev: { $stdDevSamp: "$value" },
                // Garder le premier et dernier timestamp de la fenêtre
                firstTimestamp: { $first: "$timestamp" },
                lastTimestamp: { $last: "$timestamp" },
                // Collecter les 5 premières valeurs pour référence
                sampleValues: { $push: { $slice: ["$value", 5] } }
              }
            },
            
            // Étape 3: Calculer les anomalies
            {
              $addFields: {
                isAnomaly: {
                  $or: [
                    { 
                      $gt: [
                        "$maxValue",
                        { $add: ["$avgValue", { $multiply: [2, "$stdDev"] }] }
                      ]
                    },
                    { 
                      $lt: [
                        "$minValue",
                        { $subtract: ["$avgValue", { $multiply: [2, "$stdDev"] }] }
                      ]
                    }
                  ]
                },
                // Calculer la tendance sur la fenêtre
                valueChange: {
                  $subtract: [
                    { $arrayElemAt: ["$sampleValues", -1] },
                    { $arrayElemAt: ["$sampleValues", 0] }
                  ]
                }
              }
            },
            
            // Étape 4: Projeter les champs pertinents
            {
              $project: {
                _id: 0,
                timestamp: "$_id.date",
                sensorId: "$_id.sensorId",
                location: "$_id.location",
                metrics: {
                  average: { $round: ["$avgValue", 2] },
                  max: { $round: ["$maxValue", 2] },
                  min: { $round: ["$minValue", 2] },
                  sampleCount: 1,
                  standardDeviation: { $round: ["$stdDev", 2] },
                  isAnomaly: 1,
                  valueChange: { $round: ["$valueChange", 2] },
                  timeRange: {
                    start: "$firstTimestamp",
                    end: "$lastTimestamp"
                  }
                }
              }
            },
            
            // Étape 5: Trier par date et capteur
            {
              $sort: {
                timestamp: 1,
                sensorId: 1
              }
            },
            
            // Étape 6: Optionnel - Fenêtres mobiles
            {
              $setWindowFields: {
                partitionBy: "$sensorId",
                sortBy: { timestamp: 1 },
                output: {
                  movingAvg: {
                    $avg: "$metrics.average",
                    window: {
                      documents: ["unbounded", "current"]
                    }
                  },
                  movingStdDev: {
                    $stdDevSamp: "$metrics.average",
                    window: {
                      documents: ["unbounded", "current"]
                    }
                  }
                }
              }
            }
          ]);
          
          console.log(JSON.stringify(result, null, 2));
    4. Indexation

      Types d'index

      • Index simple : Sur un champ unique
      • Index composé : Sur plusieurs champs
      • Index textuel : Pour les recherches textuelles
      • Index géospatial : Pour les données de localisation

      Création d'un index

      // 1. Création d'un index simple sur un champ unique
      // Crée un index croissant (1) sur le champ 'email'
      db.utilisateurs.createIndex({ email: 1 });
      
      // 2. Création d'un index composé sur plusieurs champs
      db.commandes.createIndex({ clientId: 1, date: -1 });
      // - clientId en ordre croissant
      // - date en ordre décroissant (pour avoir les commandes les plus récentes en premier)
      
      // 3. Création d'un index unique avec contrainte
      db.utilisateurs.createIndex(
        { username: 1 },
        { unique: true, name: "username_unique" }
      );
      
      // 4. Création d'un index TTL (Time-To-Live) pour l'expiration automatique des documents
      db.sessions.createIndex(
        { lastActivity: 1 },
        { expireAfterSeconds: 3600 * 24 * 7 } // Supprime après 7 jours d'inactivité
      );
      
      // 5. Création d'un index de texte pour la recherche plein texte
      db.articles.createIndex(
        { titre: "text", contenu: "text" },
        { weights: { titre: 3, contenu: 1 } } // Le titre a plus de poids que le contenu
      );
      
      // 6. Création d'un index géospatial 2dsphere pour les requêtes géographiques
      db.restaurants.createIndex({ localisation: "2dsphere" });
      
      // 7. Création d'un index partiel (seulement sur les documents qui correspondent au filtre)
      db.articles.createIndex(
        { vues: 1 },
        { partialFilterExpression: { etat: "publié" } }
      );
      
      // 8. Création d'un index avec options avancées
      db.produits.createIndex(
        { nom: 1, categorie: 1 },
        {
          name: "idx_nom_categorie",
          background: true,        // Construction en arrière-plan
          sparse: true,            // N'inclut que les documents où le champ existe
          collation: {             // Règles de tri spécifiques
            locale: "fr",
            strength: 2
          }
        }
      );
      
      // Vérification des index existants sur une collection
      db.utilisateurs.getIndexes();
      
      // Suppression d'un index
      db.utilisateurs.dropIndex("email_1");
      
      // Suppression de tous les index (sauf _id)
      // db.utilisateurs.dropIndexes();

      Meilleures pratiques

      • Indexer les champs fréquemment utilisés
      • Éviter les index trop complexes
      • Surveiller l'utilisation des index
      • Supprimer les index inutilisés
    5. Aggregation Pipeline

      Opérateurs principaux

      • $match : Filtrage des documents
      • $group : Agrégation de données
      • $sort : Tri des résultats
      • $project : Sélection des champs
      • $limit : Limite des résultats

      Exemple d'aggregation

      db.collection.aggregate([
        { $match: { age: { $gt: 25 } } },
        { $group: {
            _id: "$city",
            averageAge: { $avg: "$age" }
          }
        },
        { $sort: { averageAge: -1 } },
        { $limit: 5 }
      ]);
      
    6. Best Practices

      Performance

      • Utiliser des index appropriés
      • Optimiser les requêtes
      • Éviter les documents trop volumineux
      • Utiliser les projections

      Structure des données

      • Choisir une structure adaptée
      • Gérer les relations entre documents
      • Éviter les redondances inutiles
      • Documenter la structure

      Sécurité

      • Utiliser des schémas sécurisés
      • Restreindre les accès
      • Utiliser l'authentification
      • Activer l'encryption
    7. Quiz

      Quelles sont les principales opérations CRUD en MongoDB ?
    8. QCM

  2. Requêtes avancées et agrégation

    Requêtes avancées & Agrégation dans MongoDB

    Aggregation Framework

    • Pipeline de traitements sur les documents (similaire à SQL GROUP BY, HAVING, etc.)
    • Principaux stages : $match (filtrage), $group (agrégation), $project (projection de champs)
    • Stages avancés : $sort, $limit, $unwind, $lookup (jointure)
    db.commandes.aggregate([
      { $match: { statut: "livrée" } },
      { $group: { _id: "$client", total: { $sum: "$montant" } } },
      { $sort: { total: -1 } }
    ]);
    

    Optimisation des requêtes

    • Utilisation de $explain pour analyser les plans d’exécution
    • Indexation avancée : index composés, textuels, géospatiaux
    • Covered queries : requêtes totalement servies par l’index

    Transactions

    • Support des transactions multi-documents depuis MongoDB 4.x
    • Exemple :
      const session = db.getMongo().startSession();
      session.startTransaction();
      try {
        db.comptes.updateOne({ _id: 1 }, { $inc: { solde: -100 } });
        db.comptes.updateOne({ _id: 2 }, { $inc: { solde: 100 } });
        session.commitTransaction();
      } catch (e) {
        session.abortTransaction();
      }
      

    Mini-lab : Pipeline d’agrégation

    1. Télécharge un jeu de données (ex : tweets.json)
    2. Importe-le dans MongoDB : mongoimport --db test --collection tweets --file tweets.json --jsonArray
    3. Construis un pipeline d’agrégation pour compter le nombre de tweets par utilisateur :
    4. db.tweets.aggregate([
        { $group: { _id: "$user", nb: { $sum: 1 } } },
        { $sort: { nb: -1 } }
      ]);
      
    5. Modifie le pipeline pour filtrer les tweets contenant un mot-clé (ex : "mongodb")

    Quiz interactif


    1. A. $group
      B. $match
      C. $project

    2. A. $group
      B. $unwind
      C. $sort

    3. A. Filtrer les documents
      B. Sélectionner et transformer les champs
      C. Grouper les documents

    4. A. explain()
      B. aggregate()
      C. profile()

    5. A. Composé
      B. Textuel
      C. Géospatial

    6. A. Documents dupliqués
      B. Erreur de syntaxe
      C. Agrégation impossible

    7. A. 2.x
      B. 3.x
      C. 4.x

    8. A. $lookup
      B. $group
      C. $sort

    9. A. Les documents sont triés avant filtrage
      B. Le filtrage réduit le volume à trier, donc c’est plus efficace
      C. Aucun, l’ordre n’a pas d’importance

    10. A. $group: { _id: "$client", nb: { $sum: 1 } }
      B. $match: { client: ... }
      C. $project: { client: 1 }
  3. Recherche avancée : find() et findOne()

    La Commande find()

    1. Syntaxe Complète

      // Syntaxe de base de find()
      db.collection.find(
        query,                   // Critères de sélection (optionnel)
        {                         // Projection (optionnel)
          field1: 1,              // Inclure le champ (1 ou true)
          field2: 0,              // Exclure le champ (0 ou false)
          // ...
        }
      ).options();            // Options de requête
    2. Paramètres Principaux

      Paramètre Type Description Valeur par défaut
      query Document Critères de sélection (opérateurs de requête) {} (tous les documents)
      projection Document Champs à inclure/exclure (1/0 ou true/false) Tous les champs
    3. Options de Curseur

      • .limit(n) : Limite le nombre de résultats
      • .skip(n) : Saute les n premiers documents
      • .sort({field: 1/-1}) : Trie les résultats
      • .project({}) : Alternative à la projection dans find()
    4. Exemples Concrets

      // Trouver tous les documents dans une collection
      const allUsers = await db.users.find({}).toArray();
      console.log(`Nombre total d'utilisateurs: ${allUsers.length}`);
      
      // Trouver avec des critères de recherche
      const activeUsers = await db.users.find({
        status: "active",
        lastLogin: { $gt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
      }).toArray();
      
      console.log(`Utilisateurs actifs ce mois-ci: ${activeUsers.length}`);
      
      // Utilisation de la projection pour ne récupérer que certains champs
      const userEmails = await db.users.find(
        { role: "admin" },
        { 
          projection: { 
            email: 1, 
            name: 1, 
            _id: 0  // Exclure l'ID par défaut
          }
        }
      ).toArray();
      
      console.log("Emails des administrateurs:", userEmails);
      
      // Trier et limiter les résultats
      const recentOrders = await db.orders
        .find({ status: "completed" })
        .sort({ orderDate: -1 })  // -1 pour décroissant, 1 pour croissant
        .limit(10)                // Seulement les 10 premiers résultats
        .toArray();
      
      console.log("10 commandes récentes:", recentOrders);
      
      // Pagination avec skip et limit
      const page = 2;
      const perPage = 20;
      const products = await db.products
        .find({ category: "electronics" })
        .sort({ price: 1 })
        .skip((page - 1) * perPage)
        .limit(perPage)
        .toArray();
      
      console.log(`Page ${page} des produits électroniques:`, products);
      
      // Compter les documents sans les récupérer
      const inactiveUserCount = await db.users.countDocuments({ 
        status: "inactive" 
      });
      
      console.log(`Nombre d'utilisateurs inactifs: ${inactiveUserCount}`);
      
      // Utilisation de l'opérateur $in pour plusieurs valeurs
      const featuredCategories = ["Électronique", "Informatique", "Téléphonie"];
      const featuredProducts = await db.products
        .find({ 
          category: { $in: featuredCategories },
          stock: { $gt: 0 }
        })
        .toArray();
      
      console.log(`Produits en vedette en stock: ${featuredProducts.length}`);
      
      // Recherche de texte
      const searchResults = await db.articles
        .find({
          $text: { $search: "MongoDB introduction" },
          status: "published"
        })
        .sort({ score: { $meta: "textScore" } })
        .toArray();
      
      console.log(`Résultats de la recherche: ${searchResults.length} articles trouvés`);
    5. Opérateurs de Requête Courants

      • $eq : Égal à
      • $ne : Différent de
      • $gt, $gte : Plus grand (ou égal) que
      • $lt, $lte : Plus petit (ou égal) que
      • $in, $nin : Dans / pas dans un tableau
      • $and, $or, $nor : Opérateurs logiques
      • $exists : Champ existant
      • $regex : Expression régulière
      • $elemMatch : Correspondance dans un tableau
    6. Remarques Importantes

      • Les requêtes sont sensibles à la casse par défaut
      • Les index peuvent grandement améliorer les performances
      • Évitez les opérations qui scannent toute la collection (COLLSCAN)
      • Utilisez la projection pour limiter les données retournées
    7. La Méthode findOne()

      La méthode findOne() est similaire à find() mais retourne uniquement le premier document correspondant aux critères de recherche, ou null si aucun document n'est trouvé.

    8. Différences avec find()

      • Retourne un document unique plutôt qu'un curseur
      • Plus efficace lorsque vous n'avez besoin que d'un seul résultat
      • Ne nécessite pas d'appel à toArray() ou next()
      • Retourne null si aucun document n'est trouvé (au lieu d'un curseur vide)
    9. Exemples d'Utilisation

      // Trouver un utilisateur par son email
      const user = await db.users.findOne({ 
        email: "jean.dupont@example.com"
      });
      
      if (user) {
        console.log(`Utilisateur trouvé: ${user.name}`);
      } else {
        console.log("Aucun utilisateur trouvé avec cet email");
      }
      
      // Utilisation avec projection pour ne récupérer que certains champs
      const userProfile = await db.users.findOne(
        { username: "johndoe" },
        {
          projection: {
            name: 1,
            email: 1,
            lastLogin: 1,
            _id: 0
          }
        }
      );
      
      console.log("Profil utilisateur:", userProfile);
      
      // Trouver le document avec le plus grand score
      const topScore = await db.scores.findOne(
        {},
        {
          sort: { score: -1 },
          projection: { player: 1, score: 1, _id: 0 }
        }
      );
      
      console.log("Meilleur score:", topScore);
      
      // Utilisation avec des opérateurs de requête
      const recentOrder = await db.orders.findOne({
        customerId: "user123",
        status: { $in: ["processing", "shipped"] },
        orderDate: { 
          $gte: new Date(new Date() - 7 * 24 * 60 * 60 * 1000) 
        }
      }, {
        sort: { orderDate: -1 },
        projection: {
          orderId: 1,
          total: 1,
          status: 1,
          items: 1
        }
      });
      
      if (recentOrder) {
        console.log("Dernière commande récente:", recentOrder);
      }
      
      // Recherche avec un index texte
      const article = await db.articles.findOne(
        { 
          $text: { $search: "MongoDB performance" },
          status: "published"
        },
        {
          sort: { score: { $meta: "textScore" } },
          projection: {
            title: 1,
            excerpt: 1,
            score: { $meta: "textScore" },
            _id: 0
          }
        }
      );
      
      if (article) {
        console.log("Article trouvé:", article.title);
        console.log(`Score de pertinence: ${article.score.toFixed(2)}`);
      }
      
      // Utilisation avec des opérateurs de mise à jour pour une opération "trouver et mettre à jour"
      const updatedUser = await db.users.findOneAndUpdate(
        { email: "jean.dupont@example.com" },
        { $inc: { loginCount: 1 }, $set: { lastLogin: new Date() } },
        {
          returnNewDocument: true,  // Retourne le document après la mise à jour
          projection: { password: 0 }  // Exclure le mot de passe
        }
      );
      
      if (updatedUser) {
        console.log(`Bienvenue de nouveau, ${updatedUser.name}!`);
        console.log(`Nombre de connexions: ${updatedUser.loginCount}`);
      }
      

Exercices, examens et projets

Exercice

Atelier MongoDB

Concevoir un schéma documentaire et manipuler une collection.

Obligatoire Consulter
Examen

Examen MongoDB

Évaluer les requêtes, agrégations, indexations et transactions.

Obligatoire Consulter
Projet

Projet MongoDB

Développer une API documentaire avec données de démonstration.

Livrables :

  • Schéma
  • API
  • Jeu de données
Obligatoire Consulter