← Formation BDD

🍃 BD04 — MongoDB Fondamentaux

MongoDB 7 Durée : ~2h30 NoSQL · Document

1. Introduction à MongoDB

MongoDB est une base de données NoSQL orientée documents. Les données sont stockées en BSON (Binary JSON) dans des collections, sans schéma fixe obligatoire.

Concepts clés

SQLMongoDB
Base de donnéesDatabase
TableCollection
Ligne / EnregistrementDocument (BSON)
ColonneChamp (field)
JOIN$lookup (ou embedding)
INDEXIndex (B-Tree, text, geo, TTL)
PRIMARY KEY_id (ObjectId par défaut)
# Installation driver Node.js
npm install mongodb

# Connexion rapide
mongosh "mongodb://localhost:27017/myapp"

2. Documents & BSON

// Structure d'un document MongoDB
{
  _id: ObjectId("64a5f2c..."),
  name: "Alice Dupont",
  email: "alice@example.com",
  age: 28,
  tags: ["admin", "verified"],
  address: {
    street: "12 Rue de la Paix",
    city: "Paris",
    zip: "75001"
  },
  orders: [
    { orderId: 101, total: 49.99, date: ISODate("2024-01-15") }
  ],
  createdAt: ISODate("2024-01-01T00:00:00Z"),
  active: true
}

Types BSON : String, Integer (32/64-bit), Boolean, Double, Array, Object, ObjectId, Date, Null, Binary, Decimal128, Regular Expression.

3. CRUD

const { MongoClient, ObjectId } = require('mongodb');
const client = new MongoClient(process.env.MONGODB_URI);
await client.connect();
const db = client.db('myapp');
const users = db.collection('users');

// --- CREATE ---
// insertOne
const result = await users.insertOne({
  name: 'Bob Martin',
  email: 'bob@example.com',
  role: 'user',
  createdAt: new Date()
});
console.log(result.insertedId); // ObjectId

// insertMany
await users.insertMany([
  { name: 'Alice', email: 'alice@example.com' },
  { name: 'Charlie', email: 'charlie@example.com' }
]);

// --- READ ---
// findOne
const user = await users.findOne({ email: 'bob@example.com' });

// find avec filtres
const admins = await users
  .find({ role: 'admin', active: true })
  .sort({ name: 1 })
  .limit(20)
  .skip(0)
  .project({ name: 1, email: 1, _id: 0 })
  .toArray();

// findById
const byId = await users.findOne({ _id: new ObjectId('64a5f2c...') });

// --- UPDATE ---
// updateOne
await users.updateOne(
  { email: 'bob@example.com' },
  { $set: { role: 'admin', updatedAt: new Date() } }
);

// updateMany
await users.updateMany(
  { role: 'user' },
  { $set: { verified: false } }
);

// findOneAndUpdate (retourne le doc mis à jour)
const updated = await users.findOneAndUpdate(
  { _id: new ObjectId('...') },
  { $inc: { loginCount: 1 } },
  { returnDocument: 'after' }
);

// --- DELETE ---
await users.deleteOne({ _id: new ObjectId('...') });
await users.deleteMany({ active: false, createdAt: { $lt: new Date('2020-01-01') } });

4. Opérateurs de requête

Comparaison

// $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin
await products.find({
  price: { $gte: 10, $lte: 100 },
  category: { $in: ['electronics', 'gaming'] },
  stock: { $gt: 0 }
}).toArray();

// $exists, $type
await users.find({ phone: { $exists: true, $ne: null } }).toArray();

Logiques

// $and, $or, $nor, $not
await products.find({
  $or: [
    { price: { $lt: 20 } },
    { featured: true }
  ]
}).toArray();

Tableaux

// $push, $addToSet, $pull, $pop
await users.updateOne(
  { _id: userId },
  { $addToSet: { tags: 'premium' } }  // ajoute si absent
);
await users.updateOne(
  { _id: userId },
  { $pull: { tags: 'trial' } }  // supprime
);

// $elemMatch
await orders.find({
  items: { $elemMatch: { productId: 'P001', qty: { $gte: 2 } } }
}).toArray();

Mise à jour

// $set, $unset, $inc, $mul, $rename, $currentDate
await products.updateOne(
  { _id: productId },
  {
    $set: { name: 'New Name' },
    $inc: { stock: -1, viewCount: 1 },
    $currentDate: { updatedAt: true }
  }
);

5. Index MongoDB

// Index simple
await users.createIndex({ email: 1 }, { unique: true });

// Index composé
await orders.createIndex({ userId: 1, createdAt: -1 });

// Index text (full-text search)
await articles.createIndex(
  { title: 'text', body: 'text' },
  { weights: { title: 10, body: 1 }, default_language: 'french' }
);

// Recherche full-text
await articles.find({ $text: { $search: 'postgresql index' } })
  .sort({ score: { $meta: 'textScore' } })
  .toArray();

// Index TTL (expiration automatique)
await sessions.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });

// Index sparse (ignore les docs sans le champ)
await users.createIndex({ phone: 1 }, { sparse: true });

// Lister les index
await users.listIndexes().toArray();

// Supprimer un index
await users.dropIndex('email_1');

6. Design de schéma

Embedding vs Références

CritèreEmbedding (imbriqué)Référence (_id)
Lecture1 requête2 requêtes / $lookup
Mise à jour partagéeDifficile (dupliqué)Facile (1 endroit)
Cardinalité1:few (< quelques dizaines)1:many (milliers+)
Taille docPeut dépasser 16 MoStable
// Embedding (1-to-few) — adresse dans user
{ _id: ..., name: 'Alice', address: { street: '...', city: 'Paris' } }

// Référence (1-to-many) — orders dans collection séparée
{ _id: ..., userId: ObjectId('...'), total: 49.99, items: [...] }