Maîtrise des opérations CRUD MongoDB : Guide pratique des commandes

Découvrez la puissance de MongoDB avec ce guide pratique des opérations CRUD essentielles. Apprenez à gérer efficacement vos données à l'aide des commandes `insert`, `find`, `update` et `delete`. Cet article fournit des explications claires, des exemples concrets et les bonnes pratiques pour créer, lire, mettre à jour et supprimer des documents dans vos collections MongoDB. Parfait pour les développeurs et les administrateurs, c'est votre ressource de référence pour maîtriser la manipulation des données avec MongoDB.

Maîtrise des opérations CRUD MongoDB : Guide pratique des commandes

MongoDB, une base de données NoSQL documentaire populaire, constitue le socle d'innombrables applications modernes grâce à sa flexibilité, son évolutivité et ses performances. Au cœur de l'interaction avec toute base de données se trouvent les opérations fondamentales Créer, Lire, Mettre à jour et Supprimer (CRUD). Maîtriser ces commandes est essentiel pour quiconque travaille avec MongoDB, qu'il s'agisse de développeurs créant de nouvelles fonctionnalités ou d'administrateurs gérant les données.

Ce guide utilise une petite collection users et présente les commandes CRUD MongoDB auxquelles vous recourrez lors de travaux réels : ajouter un enregistrement à partir d'un formulaire d'inscription, trouver le document derrière un ticket de support, modifier un champ sans écraser le reste du document, et supprimer des données sans effacer accidentellement la collection. Les exemples utilisent mongosh, mais les mêmes filtres et opérateurs de mise à jour s'appliquent aux pilotes d'application.

Prérequis

Avant de plonger dans les commandes, assurez-vous d'avoir :

  • MongoDB installé et en cours d'exécution : Vous pouvez le télécharger depuis le site officiel de MongoDB ou utiliser un service cloud comme MongoDB Atlas.
  • mongosh (MongoDB Shell) installé : Il s'agit de l'interface JavaScript interactive pour MongoDB.

Connexion à MongoDB et sélection d'une base de données

Pour commencer, ouvrez votre terminal ou invite de commandes et connectez-vous à votre instance MongoDB à l'aide de mongosh :

mongosh

Une fois connecté, vous serez dans la base de données test par défaut. Pour basculer vers une nouvelle base de données ou en créer une, utilisez la commande use :

use myDatabase;

Si myDatabase n'existe pas, MongoDB la créera implicitement lorsque vous insérerez votre premier document dans une collection à l'intérieur de celle-ci.

Opérations de création (Insertion)

Les opérations de création consistent à ajouter de nouveaux documents à une collection. MongoDB fournit des méthodes pour insérer un ou plusieurs documents.

1. db.collection.insertOne()

Cette méthode insère un seul document dans une collection. Si la collection n'existe pas, MongoDB la crée.

// Sélectionnez une collection nommée 'users'
db.users.insertOne({
  name: "Alice Smith",
  age: 30,
  city: "New York",
  email: "[email protected]",
  interests: ["reading", "hiking"]
});

La sortie affichera le statut acknowledged et l'insertedId du nouveau document.

2. db.collection.insertMany()

Utilisez cette méthode pour insérer plusieurs documents dans une collection en une seule opération. Elle prend un tableau de documents.

db.users.insertMany([
  {
    name: "Bob Johnson",
    age: 24,
    city: "Los Angeles",
    email: "[email protected]",
    interests: ["coding", "gaming"]
  },
  {
    name: "Charlie Brown",
    age: 35,
    city: "New York",
    email: "[email protected]",
    interests: ["cooking", "photography"]
  },
  {
    name: "Diana Prince",
    age: 29,
    city: "London",
    email: "[email protected]",
    interests: ["fitness", "travel"]
  }
]);

Cela retournera un tableau d'insertedIds pour tous les documents ajoutés.

Astuce : MongoDB ajoute automatiquement un champ _id (un ObjectId unique) à chaque document si vous n'en fournissez pas.

Opérations de lecture (Recherche)

Les opérations de lecture consistent à interroger des documents dans une collection. La méthode find() est votre outil principal pour cela.

1. db.collection.find()

a. Trouver tous les documents

Pour récupérer tous les documents d'une collection, appelez find() sans aucun argument :

db.users.find();

b. Trouver des documents avec un filtre de requête

Passez un document de requête à find() pour spécifier des critères de sélection des documents. Cela agit comme une clause WHERE en SQL.

// Trouver les utilisateurs de New York
db.users.find({ city: "New York" });

// Trouver les utilisateurs de plus de 25 ans
db.users.find({ age: { $gt: 25 } });

// Trouver les utilisateurs dont l'âge est compris entre 25 et 35 ans (excluant 35)
db.users.find({ age: { $gt: 25, $lt: 35 } });

// Trouver les utilisateurs dont les intérêts incluent 'coding'
db.users.find({ interests: "coding" });

// Trouver les utilisateurs dont les intérêts incluent À LA FOIS 'reading' et 'hiking'
db.users.find({ interests: { $all: ["reading", "hiking"] } });

// Trouver les utilisateurs nommés Alice Smith OU de Londres
db.users.find({
  $or: [
    { name: "Alice Smith" },
    { city: "London" }
  ]
});

Opérateurs de requête courants :

  • $eq : Égal à (par défaut si aucun opérateur n'est spécifié)
  • $ne : Différent de
  • $gt : Supérieur à
  • $gte : Supérieur ou égal à
  • $lt : Inférieur à
  • $lte : Inférieur ou égal à
  • $in : Correspond à l'une des valeurs spécifiées dans un tableau
  • $nin : Ne correspond à aucune des valeurs spécifiées dans un tableau
  • $and, $or, $not, $nor : Opérateurs logiques

c. Projection : Sélection de champs spécifiques

Pour ne retourner qu'un sous-ensemble de champs, passez un document de projection comme deuxième argument à find(). Une valeur de 1 inclut le champ, 0 l'exclut. Le champ _id est inclus par défaut sauf s'il est explicitement exclu.

// Retourner uniquement le nom et l'email, exclure _id
db.users.find({ city: "New York" }, { name: 1, email: 1, _id: 0 });

d. Tri, limitation et saut

L'enchaînement des méthodes permet des requêtes plus complexes :

// Trier par âge décroissant (1 pour croissant, -1 pour décroissant)
db.users.find().sort({ age: -1 });

// Limiter les résultats à 2 documents
db.users.find().limit(2);

// Sauter les 2 premiers documents et retourner le reste
db.users.find().skip(2);

// Combiner les opérations : Trouver les utilisateurs de New York, trier par âge, sauter 1, limiter à 1
db.users.find({ city: "New York" }).sort({ age: 1 }).skip(1).limit(1);

2. db.collection.findOne()

Cette méthode retourne un seul document qui correspond aux critères de la requête. Si plusieurs documents correspondent, elle retourne le premier trouvé.

db.users.findOne({ name: "Alice Smith" });

Opérations de mise à jour

Les opérations de mise à jour modifient les documents existants dans une collection. Vous pouvez mettre à jour un seul document, plusieurs documents, ou même remplacer un document entier.

1. db.collection.updateOne()

Met à jour un seul document qui correspond aux critères du filtre.

// Mettre à jour la ville d'Alice à 'San Francisco'
db.users.updateOne(
  { name: "Alice Smith" },
  { $set: { city: "San Francisco", lastUpdated: new Date() } }
);

2. db.collection.updateMany()

Met à jour tous les documents qui correspondent aux critères du filtre.

// Incrémenter l'âge de tous les utilisateurs de New York de 1
db.users.updateMany(
  { city: "New York" },
  { $inc: { age: 1 } }
);

// Ajouter un nouvel intérêt 'reading' aux utilisateurs qui ne l'ont pas déjà
db.users.updateMany(
  {}, // Appliquer à tous les documents
  { $addToSet: { interests: "reading" } }
);

// Supprimer 'gaming' des intérêts de Bob Johnson
db.users.updateOne(
  { name: "Bob Johnson" },
  { $pull: { interests: "gaming" } }
);

Opérateurs de mise à jour courants :

  • $set : Définit la valeur d'un champ dans un document. Crée le champ s'il n'existe pas.
  • $inc : Incrémente la valeur d'un champ d'un montant spécifié.
  • $unset : Supprime un champ d'un document.
  • $push : Ajoute une valeur à un champ de type tableau.
  • $pull : Supprime toutes les instances d'une valeur ou de valeurs correspondant à une requête spécifiée d'un tableau.
  • $addToSet : Ajoute une valeur à un tableau uniquement si la valeur n'est pas déjà présente.

3. db.collection.replaceOne()

Remplace un seul document qui correspond aux critères du filtre par un nouveau document. Le champ _id du document remplacé ne peut pas être modifié.

// Remplacer entièrement le document de Bob Johnson
db.users.replaceOne(
  { name: "Bob Johnson" },
  {
    name: "Robert Johnson",
    occupation: "Software Engineer",
    status: "active",
    email: "[email protected]"
  }
);

Option Upsert

Les deux méthodes updateOne() et updateMany() prennent en charge une option upsert. Si elle est définie sur true et qu'aucun document ne correspond au filtre, MongoDB insérera un nouveau document basé sur la requête et les opérations de mise à jour.

db.users.updateOne(
  { name: "David Lee" },
  { $set: { age: 28, city: "Seattle" } },
  { upsert: true } // Si David Lee n'existe pas, le créer
);

Opérations de suppression

Les opérations de suppression suppriment des documents d'une collection. Soyez extrêmement prudent avec les opérations de suppression, car elles sont irréversibles.

1. db.collection.deleteOne()

Supprime au plus un document qui correspond au filtre spécifié.

// Supprimer l'utilisateur nommé 'Robert Johnson' (anciennement 'Bob Johnson')
db.users.deleteOne({ name: "Robert Johnson" });

2. db.collection.deleteMany()

Supprime tous les documents qui correspondent au filtre spécifié.

// Supprimer tous les utilisateurs de Londres
db.users.deleteMany({ city: "London" });

Avertissement : Pour supprimer tous les documents d'une collection, utilisez un filtre vide {}. Soyez extrêmement prudent car cette opération ne peut pas être annulée :

db.users.deleteMany({}); // Supprime tous les documents de la collection 'users'

3. db.collection.drop()

Cette méthode supprime définitivement une collection entière de la base de données, y compris tous ses documents et index.

db.users.drop(); // Supprime toute la collection 'users'

Avertissement : Supprimer une collection est une opération hautement destructrice. Assurez-vous d'avoir des sauvegardes appropriées ou d'être absolument certain avant d'exécuter cette commande.

Bonnes pratiques pour les opérations CRUD MongoDB

  • Indexation : Pour les champs fréquemment interrogés, créez des index pour accélérer considérablement les opérations de lecture. db.collection.createIndex({ fieldName: 1 }).
  • Projections : Ne récupérez que les données dont vous avez besoin. L'utilisation de projections ({ field: 1 }) réduit la bande passante réseau et l'utilisation de la mémoire.
  • Opérations par lots : Lors de l'insertion, de la mise à jour ou de la suppression de nombreux documents, utilisez insertMany(), updateMany() et deleteMany() au lieu d'opérations individuelles pour réduire les frais généraux.
  • Comprendre les opérateurs : Familiarisez-vous avec l'ensemble riche des opérateurs de requête et de mise à jour de MongoDB. Ils offrent des moyens puissants de manipuler vos données.
  • Gestion des erreurs : Dans une application de production, implémentez toujours une gestion robuste des erreurs pour vos opérations de base de données.
  • Conception de schéma : Bien que MongoDB soit sans schéma, une conception de schéma réfléchie est cruciale pour des requêtes efficaces et la cohérence des données.

Une façon plus sûre de pratiquer les opérations CRUD dans une base de données réelle

La partie dangereuse des opérations CRUD MongoDB n'est pas la syntaxe. C'est l'exécution d'un filtre trop large dans la mauvaise base de données, surtout avec updateMany() ou deleteMany(). J'aime utiliser une habitude en trois étapes pour toute écriture qui touche des données existantes.

D'abord, exécutez le filtre comme une lecture :

db.users.find(
  { city: "New York", status: "inactive" },
  { name: 1, email: 1, city: 1, status: 1 }
).limit(20);

Si l'aperçu retourne des documents auxquels vous ne vous attendiez pas, arrêtez-vous là. Corrigez le filtre avant de penser à la mise à jour. S'il ne retourne rien, assurez-vous d'être dans la bonne base de données avec db.getName() et que les noms de champs correspondent aux documents réels.

Deuxièmement, comptez les documents correspondants :

db.users.countDocuments({ city: "New York", status: "inactive" });

Cela vous donne une estimation approximative de l'impact. Si vous vous attendiez à 12 utilisateurs et que le compte indique 12 000, la commande vous dit que quelque chose ne va pas. Un compte ne remplace pas une sauvegarde, mais c'est une barrière de sécurité peu coûteuse.

Troisièmement, exécutez l'écriture avec la commande la plus étroite qui convient à la tâche. Utilisez updateOne() lorsqu'un email unique, un identifiant de compte ou _id doit correspondre à un seul document. Utilisez updateMany() uniquement lorsque la modification d'un segment entier est intentionnelle.

db.users.updateMany(
  { city: "New York", status: "inactive" },
  {
    $set: {
      marketingEmailEnabled: false,
      updatedBy: "ops-maintenance-2025-11-04"
    }
  }
);

Ajouter un updatedBy, updatedAt ou une note de maintenance n'est pas requis par MongoDB, mais cela aide plus tard quand quelqu'un demande pourquoi un champ a changé.

Erreurs courantes qui causent de vrais bugs

La première erreur est de remplacer un document alors que vous vouliez mettre à jour un champ. Cette commande semble inoffensive, mais elle remplace le document correspondant entier avec seulement les champs affichés :

db.users.updateOne(
  { email: "[email protected]" },
  { city: "Boston" }
);

MongoDB moderne attend des opérateurs de mise à jour pour les documents de mise à jour, sauf si vous utilisez des méthodes de type remplacement, donc ce modèle peut échouer selon la commande et la version. Le modèle mental plus sûr est simple : si vous modifiez des champs sur place, utilisez $set, $unset, $inc, $push, $pull ou un autre opérateur de mise à jour.

db.users.updateOne(
  { email: "[email protected]" },
  { $set: { city: "Boston" } }
);

La deuxième erreur est d'interroger des tableaux comme si l'ordre importait toujours. { interests: ["reading", "hiking"] } correspond exactement à un tableau. { interests: "reading" } correspond aux documents où le tableau contient cette valeur. { interests: { $all: ["reading", "hiking"] } } correspond aux tableaux qui contiennent les deux valeurs, quel que soit l'ordre. Ce sont trois questions différentes.

La troisième erreur est de supposer que findOne() retourne "le bon" lorsque le filtre n'est pas unique. Si vous exécutez :

db.users.findOne({ city: "New York" });

MongoDB retourne un document correspondant, mais sans un tri, vous ne devriez pas traiter ce document comme le plus récent, le plus ancien, le plus important ou le plus représentatif. Si l'ordre compte, dites-le :

db.users.find({ city: "New York" }).sort({ createdAt: -1 }).limit(1);

La quatrième erreur est de sauter les index jusqu'à ce que l'application soit déjà lente. Une collection avec quelques milliers de documents peut cacher une requête inefficace. La même requête peut devenir pénible lorsque la collection grandit. Si l'application trouve fréquemment des utilisateurs par email, créez un index unique lorsque le modèle de données le permet :

db.users.createIndex({ email: 1 }, { unique: true });

Cela protège à la fois les performances et la qualité des données. Si des emails en double existent déjà, la commande échouera, ce qui est exactement le genre de problème que vous voulez découvrir avant de compter sur l'email comme identifiant.

Vérifier ce qu'une écriture a réellement fait

Les résultats d'écriture MongoDB méritent d'être lus. Après une mise à jour, regardez matchedCount et modifiedCount. matchedCount vous indique combien de documents ont correspondu au filtre. modifiedCount vous indique combien ont été réellement modifiés.

Si matchedCount est 1 et modifiedCount est 0, la commande peut encore être correcte. Peut-être que le champ avait déjà la valeur demandée. Si matchedCount est 0, votre filtre n'a correspondu à rien. C'est courant lorsqu'un _id est passé comme une chaîne au lieu d'un ObjectId.

db.users.findOne({ _id: ObjectId("6650f1e59d0a41a37c2d8011") });

Pour les suppressions, vérifiez deletedCount. Si vous vous attendiez à un document supprimé et que le résultat indique deletedCount: 0, n'exécutez pas immédiatement une suppression plus large. Revérifiez la base de données, la collection et le filtre.

Quand les opérations CRUD ne suffisent pas

Les commandes CRUD de base couvrent la plupart des travaux quotidiens sur les données, mais certaines tâches nécessitent des outils plus puissants. Si vous mettez à jour plusieurs collections qui doivent rester cohérentes ensemble, regardez les transactions sur les jeux de réplicas ou les clusters fragmentés. Si vous remodelez des données sur plusieurs documents, un pipeline d'agrégation peut être plus clair qu'une longue série de boucles côté client. Si vous migrez des données de production, utilisez un script avec journalisation, mode dry-run, sauvegardes et un plan de restauration.

Pour les opérations ponctuelles dans mongosh, gardez les commandes lisibles. Une ligne astucieuse est plus difficile à réviser et plus difficile à récupérer. En production, les commandes ennuyeuses sont généralement meilleures.

Les commandes CRUD MongoDB sont simples une fois que vous vous êtes habitué aux documents, aux filtres et aux opérateurs de mise à jour. La compétence qui compte dans le travail réel est d'être délibéré : prévisualiser le filtre, compter l'impact, choisir la commande d'écriture la plus étroite, lire le résultat et laisser suffisamment de contexte pour que la personne suivante puisse comprendre ce qui a changé.