OUJOOD.COM
Introduction : Pourquoi Intégrer MongoDB à ExpressJS ?
Une base de données persistante est le cœur de toute application web dynamique. Contrairement aux variables JavaScript qui s'effacent à chaque redémarrage serveur, une base de données conserve vos informations durablement. ExpressJS, framework minimaliste pour Node.js, devient puissant couplé à un système de stockage robuste. Ce guide vous apprend à construire une application complète capable de sauvegarder, modifier, récupérer et supprimer des données en temps réel.
Nous utiliserons MongoDB, base de données NoSQL orientée documents dont la structure JSON-like est naturellement compatible avec JavaScript. Associée à Mongoose (ODM : Object Data Modeling), vous bénéficierez d'une validation automatique, de schémas typés et d'une API élégante. Ce trio Node.js + ExpressJS + MongoDB est l'un des plus utilisés en développement web en 2026.
Étape 1 : Préparer l'Environnement Node.js + MongoDB
Voici les prérequis indispensables pour connecter ExpressJS à MongoDB :
- Node.js 18 LTS ou supérieur (recommandé 2026) : Vérifiez l'installation avec
node -vetnpm -v. - Initialisation npm : Créez un dossier projet, exécutez
npm init -ypour générerpackage.json. - Installation des dépendances :
npm install express mongoose dotenv. Dotenv sécurise vos variables d'environnement. - MongoDB Community Edition 7.x : Démarrez avec
mongod(Windows) oubrew services start mongodb-community(macOS). - MongoDB Compass (GUI officielle) : Visualisez et déboguez vos collections sans ligne de commande.
Mise à jour 2026 : Les options useNewUrlParser et useUnifiedTopology sont supprimées dans Mongoose 7+. La connexion est plus simple et stable par défaut.
Étape 2 : Connexion ExpressJS–MongoDB avec Mongoose 7+
Connexion Simplifiée (Syntaxe 2026)
Créez server.js à la racine de votre projet. Mongoose gère automatiquement le pool de connexions, les reconnexions et les timeouts. L'exemple ci-dessous reflète la syntaxe recommandée en 2026, sans les options dépréciées :
// Importation des modules (syntaxe CommonJS Node.js) var express = require('express'); var mongoose = require('mongoose'); // Chargement des variables .env en premier — avant toute autre instruction require('dotenv').config(); var app = express(); // Connexion MongoDB : plus besoin de useNewUrlParser/useUnifiedTopology en Mongoose 7+ // Fallback sur l'URI locale si MONGODB_URI n'est pas définie dans .env mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/mon_db') .then(() => console.log("Connecte a MongoDB")) .catch(err => console.log("Erreur MongoDB : ", err)); // Port depuis variable d'environnement ou 3000 par défaut var PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log("Serveur sur http://localhost:" + PORT));
- mongodb://localhost:27017 : URL du serveur MongoDB local sur le port par défaut
- mon_db : Nom de la base — créée automatiquement si elle n'existe pas
- dotenv : Charge les variables depuis
.env— à appeler en toute première ligne - Mongoose 7+ : Options dépréciées retirées, connexion plus lisible et stable
Étape 3 : Schéma Mongoose avec Validation Avancée
Définir un Modèle Utilisateur Robuste
Un schéma Mongoose est le contrat qui définit structure, types et règles de validation de vos documents. Bien que MongoDB soit nativement "schema-less", Mongoose apporte une couche de validation côté application, garantissant l'intégrité des données avant insertion. C'est pourquoi Mongoose est incontournable dans tout projet Node.js sérieux.
var express = require('express');
var mongoose = require('mongoose');
require('dotenv').config();
var app = express();
// Middlewares : déclarés AVANT toutes les routes (sinon req.body sera undefined)
// urlencoded parse les formulaires HTML, json parse les API REST
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/mon_db')
.then(() => console.log("MongoDB connecte")).catch(err => console.log(err));
// Schéma Mongoose : chaque propriété est typée avec des contraintes de validation
var utilisateurSchema = new mongoose.Schema({
nom: {
type: String,
trim: true, // Supprime les espaces superflus avant/après la chaîne
minlength: [2, 'Le nom doit contenir au moins 2 caracteres']
},
email: {
type: String,
required: [true, "L'email est obligatoire"], // Message d'erreur personnalisé
unique: true, // Crée un index MongoDB — doublon déclenche code 11000
lowercase: true, // "Alice@Gmail.COM" devient "alice@gmail.com"
trim: true,
match: [/^[^\s@]+@[^\s@]+\.[^\s@]+$/, "Format d'email invalide"]
}
}, { timestamps: true }); // Ajoute createdAt et updatedAt automatiquement
// Modèle Mongoose : 'Utilisateur' → collection 'utilisateurs' dans MongoDB
var Utilisateur = mongoose.model('Utilisateur', utilisateurSchema);
app.get('/', (req, res) => {
res.send(`<form method="POST" action="/ajouter">
<input type="text" name="nom" placeholder="Nom" required>
<input type="email" name="email" placeholder="Email" required>
<button>Enregistrer</button></form>`);
});
app.post('/ajouter', function(req, res) {
// Déstructuration sécurisée : on extrait uniquement les champs attendus de req.body
var { nom, email } = req.body;
new Utilisateur({ nom, email }).save()
.then(() => res.send("Utilisateur enregistre ! <a href='/'>Retour</a>"))
.catch(function(err) {
// Code 11000 : violation de l'index unique sur email (géré côté MongoDB)
if (err.code === 11000) return res.send("Email deja utilise");
// ValidationError : règle du schéma non respectée (format, required, minlength)
if (err.name === 'ValidationError') return res.send("<pre>" + JSON.stringify(err.errors, null, 2) + "</pre>");
res.send("Erreur : " + err);
});
});
app.listen(process.env.PORT || 3000, () => console.log("Serveur demarre"));
- Parsing :
express.urlencodedpeuplereq.bodyavec les champs du formulaire - Instanciation :
new Utilisateur()crée un objet Mongoose (pas encore en base) - Validation :
.save()déclenche toutes les règles du schéma avant INSERT - Insertion : Si validation OK, Mongoose insère le document dans MongoDB
- Réponse : Message de succès ou erreur typée renvoyé au client
Étape 4 : CRUD Complet — Create, Read, Update, Delete
Application ExpressJS + MongoDB avec les 4 Opérations CRUD
Le CRUD représente les quatre opérations fondamentales sur une base de données. Voici une implémentation complète utilisant les méthodes Mongoose optimales en 2026 : find(), findById(), findByIdAndUpdate() et findByIdAndDelete().
var express = require('express');
var mongoose = require('mongoose');
require('dotenv').config();
var app = express();
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/mon_db')
.then(() => console.log("MongoDB connecte")).catch(err => console.log(err));
var utilisateurSchema = new mongoose.Schema({
nom: { type: String, trim: true, minlength: [2, 'Nom trop court'] },
email: { type: String, required: true, unique: true, lowercase: true, trim: true,
match: [/^[^\s@]+@[^\s@]+\.[^\s@]+$/, 'Format email invalide'] }
}, { timestamps: true });
var Utilisateur = mongoose.model('Utilisateur', utilisateurSchema);
// CREATE GET : formulaire d'ajout avec lien vers la liste
app.get('/', (req, res) => res.send(`<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"></head>
<body><h1>Ajouter un Utilisateur</h1>
<form method="POST" action="/ajouter">
<input type="text" name="nom" placeholder="Nom complet" required>
<input type="email" name="email" placeholder="Email" required>
<button type="submit">Enregistrer</button></form>
<a href="/liste">Voir la liste</a></body></html>`));
// CREATE POST : sauvegarde — extraction sécurisée des champs attendus uniquement
app.post('/ajouter', function(req, res) {
new Utilisateur({ nom: req.body.nom, email: req.body.email }).save()
.then(() => res.send("Enregistre ! <a href='/liste'>Liste</a>"))
.catch(function(err) {
if (err.code === 11000) return res.send("Email deja utilise <a href='/'>Retour</a>");
if (err.name === 'ValidationError') return res.send("<pre>" + JSON.stringify(err.errors, null, 2) + "</pre>");
res.send("Erreur : " + err);
});
});
// READ : liste triée par date décroissante — sort(-1) = plus récents en premier
app.get('/liste', function(req, res) {
Utilisateur.find().sort({ createdAt: -1 })
.then(function(users) {
var html = "<h1>Utilisateurs</h1><ul>";
users.forEach(function(u) {
html += "<li><strong>" + u.nom + "</strong> " + u.email;
html += " <a href='/modifier/" + u._id + "'>Modifier</a>";
// confirm() côté client évite les suppressions accidentelles
html += " <a href='/supprimer/" + u._id + "' onclick=\"return confirm('Supprimer ?')\">Supprimer</a></li>";
});
res.send(html + "</ul><a href='/'>Accueil</a>");
})
.catch(err => res.send("Erreur : " + err));
});
// DELETE : findByIdAndDelete — opération atomique, retourne le doc supprimé
app.get('/supprimer/:id', function(req, res) {
Utilisateur.findByIdAndDelete(req.params.id)
.then(doc => doc ? res.send(doc.nom + " supprime <a href='/liste'>Retour</a>") : res.send("Introuvable"))
.catch(err => res.send("Erreur : " + err));
});
// UPDATE GET : formulaire pré-rempli via findById
app.get('/modifier/:id', function(req, res) {
Utilisateur.findById(req.params.id)
.then(u => {
if (!u) return res.send("Introuvable <a href='/liste'>Retour</a>");
res.send(`<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>
<h1>Modifier ${u.nom}</h1>
<form method="POST" action="/modifier/${u._id}">
<input type="text" name="nom" value="${u.nom}" required>
<input type="email" name="email" value="${u.email}" required>
<button>Enregistrer</button>
</form><a href="/liste">Annuler</a></body></html>`);
})
.catch(err => res.send("Erreur : " + err));
});
// UPDATE POST : findByIdAndUpdate
// new:true retourne le doc APRES modification (défaut : avant)
// runValidators:true CRUCIAL — force la validation du schéma lors des updates (désactivé par défaut !)
app.post('/modifier/:id', function(req, res) {
Utilisateur.findByIdAndUpdate(req.params.id,
{ nom: req.body.nom, email: req.body.email },
{ new: true, runValidators: true })
.then(doc => doc ? res.send(doc.nom + " mis a jour <a href='/liste'>Retour</a>") : res.send("Introuvable"))
.catch(function(err) {
if (err.code === 11000) return res.send("Email deja utilise <a href='/liste'>Retour</a>");
if (err.name === 'ValidationError') return res.send("<pre>" + JSON.stringify(err.errors, null, 2) + "</pre>");
res.send("Erreur : " + err);
});
});
app.listen(process.env.PORT || 3000, () => console.log("CRUD actif : /, /liste, /modifier/:id, /supprimer/:id"));
Points Techniques Clés du CRUD Mongoose
L'option runValidators dans findByIdAndUpdate
C'est le piège le plus fréquent : par défaut, findByIdAndUpdate() ne déclenche pas la validation du schéma Mongoose. Sans { runValidators: true }, un email malformé ou un champ requis manquant sera enregistré sans erreur. Ajoutez toujours cette option pour garantir l'intégrité des données lors des mises à jour.
findByIdAndDelete vs deleteOne
findByIdAndDelete(id) retourne le document supprimé, permettant d'afficher son nom en confirmation. deleteOne() retourne seulement un statut sans le document. Préférez la première pour une meilleure expérience utilisateur.
Tri .sort() et pagination
.sort({ createdAt: -1 }) trie par date décroissante (plus récents en premier). Pour paginer : .skip((page-1)*10).limit(10) combiné à countDocuments() pour calculer le nombre total de pages.
Gestion Professionnelle des Erreurs MongoDB
Erreur 11000 — Violation de Clé Unique
Cause : Tentative d'insertion d'un email déjà présent. L'unicité est un index MongoDB côté base, pas une règle Mongoose — d'où le code distinct err.code === 11000. Affichez un message clair et proposez la récupération de compte.
ValidationError — Données Non Conformes au Schéma
Cause : email sans @, champ required vide, nom trop court. L'objet err.errors contient un sous-objet par champ en erreur avec un message lisible. Parsez-le pour afficher des messages ciblés dans votre interface.
CastError — Identifiant MongoDB Invalide
Cause : L'URL contient un :id non valide (pas un ObjectID de 24 caractères hex). Prévenez avec mongoose.Types.ObjectId.isValid(req.params.id) avant d'appeler findById().
Sécurité et Variables d'Environnement en Production
Ne jamais coder en dur l'URI MongoDB dans le source. Créez un fichier .env à la racine :
MONGODB_URI=mongodb://localhost:27017/mon_db(local) ou l'URI Atlas pour la productionPORT=3000
Chargez avec require('dotenv').config(); en première ligne. Ajoutez .env à .gitignore impérativement. Pour MongoDB Atlas : mongodb+srv://user:password@cluster0.xxxxx.mongodb.net/mon_db.
Packages de sécurité essentiels : Helmet.js (app.use(require('helmet')())), express-rate-limit contre le brute-force, express-validator pour la sanitization côté serveur, et CORS pour les API REST.
Vérifier vos Données avec MongoDB Compass
Connectez-vous à mongodb://localhost:27017, sélectionnez mon_db, ouvrez la collection utilisateurs. Testez en temps réel : ajoutez un utilisateur, rafraîchissez Compass pour voir le document avec _id, createdAt, updatedAt. Filtrez par email : { "email": "test@example.com" }. Vérifiez l'onglet "Indexes" : l'index unique sur email doit être créé automatiquement par Mongoose.
Fonctionnalités Avancées : Pagination, Recherche et Relations
Pagination : Utilisateur.find().sort({ createdAt: -1 }).skip((page-1)*10).limit(10) avec req.query.page comme numéro de page et countDocuments() pour le total. Recherche insensible à la casse : Utilisateur.find({ $or: [{ nom: { $regex: terme, $options: 'i' } }, { email: { $regex: terme, $options: 'i' } }] }). Relations entre collections : déclarez auteur: { type: mongoose.Schema.Types.ObjectId, ref: 'Utilisateur' } dans votre schéma Article, puis Article.find().populate('auteur', 'nom email') résout automatiquement la référence.
Conclusion et Prochaines Étapes
Vous maîtrisez maintenant l'intégration complète de MongoDB avec ExpressJS via Mongoose : connexion robuste, schémas validés, CRUD complet avec gestion des erreurs typées, sécurisation des credentials et visualisation avec Compass.
- Authentification JWT : sécurisez vos routes avec
jsonwebtoken - API REST pure : retournez du JSON pour un backend découplé React/Vue
- MongoDB Atlas : déployez en cloud avec backups automatiques et monitoring
- Tests automatisés : Jest + Supertest pour la non-régression de vos routes
Par carabde | Mis à jour le 17 février 2026