Validateurs integres a Mongoose : required, min/max (Number), minlength/maxlength (String), enum, match (regex). Ils s'executent automatiquement avant la sauvegarde.
Un videur qui verifie ta carte d'identite, ta tenue et ta reservation avant de te laisser entrer.
{
age: { type: Number, min: 0, max: 150 },
role: { type: String, enum: ['user', 'admin'] },
name: { type: String, minlength: 2 }
}Cas d'usage : Valider les donnees utilisateur avant de les persister en base sans logique custom.
Objet qui gere la connexion a MongoDB. Mongoose maintient un pool de connexions et un buffer des operations en attente jusqu'a ce que la connexion soit etablie.
Le fil du telephone entre ton appli et la base de donnees, avec une ligne d'attente integree.
await mongoose.connect(
'mongodb://localhost:27017/mydb',
{ maxPoolSize: 10 }
);
mongoose.connection.on('error', console.error);Cas d'usage : Initialiser la connexion a la base au demarrage de l'application NestJS ou Express.
Fonctions de validation personnalisees definies dans le schema. Peuvent etre synchrones ou asynchrones et retournent un booleen ou lancent une erreur.
Un test sur mesure en plus des controles standard : verifier que le code postal correspond bien a la ville.
{
phone: {
type: String,
validate: {
validator: (v) => /^\+33[0-9]{9}$/.test(v),
message: 'Format FR invalide'
}
}
}Cas d'usage : Valider des regles metier specifiques comme un format de telephone, une plage de dates ou un IBAN.
Mecanisme d'heritage de schema qui permet de stocker des documents de types differents dans une meme collection, avec un champ discriminateur (__t) pour differencier les types.
Un parking multi-vehicules : voitures, motos et camions partagent le meme espace mais ont des regles differentes.
const Event = mongoose.model('Event', eventSchema);
const Click = Event.discriminator('Click',
new Schema({ url: String })
);
const Purchase = Event.discriminator('Purchase',
new Schema({ amount: Number })
);Cas d'usage : Modeliser un systeme d'evenements (analytics) ou des entites polymorphiques dans une seule collection.
Les Document middlewares (save, validate, remove) ont this = le document. Les Query middlewares (find, update, delete) ont this = la query. Important pour savoir quoi modifier.
Document middleware = le chirurgien qui opere directement le patient. Query middleware = le pharmacien qui modifie l'ordonnance.
// Document: this = document
schema.pre('save', function() {
console.log(this.name);
});
// Query: this = query
schema.pre('find', function() {
this.where({ deleted: false });
});Cas d'usage : Implementer du soft-delete en filtrant automatiquement les documents supprimes sur chaque find.
Mongoose permet de definir les index directement dans le schema avec index: true, unique: true ou via schema.index(). Les index sont synchronises au demarrage de l'app.
Declarer les index dans le plan (schema) pour que l'architecte (MongoDB) les construise automatiquement.
userSchema.index(
{ email: 1 },
{ unique: true }
);
userSchema.index(
{ lastName: 1, firstName: 1 }
);Cas d'usage : Gerer les index dans le code applicatif pour les versionner avec Git.
Methode qui retourne des objets JavaScript bruts au lieu d'instances Mongoose. 2 a 5x plus rapide car elle saute l'hydratation, les getters et les virtuals.
Commander un plat a emporter sans assiette ni couverts : plus leger et plus rapide a servir.
const users = await User
.find({ status: 'active' })
.lean();
// users[0].save() -> Error (pas un doc Mongoose)Cas d'usage : API en lecture seule ou les donnees sont serialisees en JSON sans modification.
Fonctions executees avant (pre) ou apres (post) certaines operations comme save, validate, remove ou find. Permettent d'injecter de la logique transversale.
Les controles de securite a l'aeroport (pre) et le tapis a bagages (post) : ils s'executent automatiquement autour de ton vol.
userSchema.pre('save', async function() {
if (this.isModified('password')) {
this.password = await bcrypt.hash(
this.password, 10
);
}
});Cas d'usage : Hasher les mots de passe avant sauvegarde, logger les operations ou mettre a jour des timestamps.
Classe construite a partir d'un Schema qui fournit l'interface CRUD pour interagir avec une collection MongoDB. Chaque instance d'un Model est un document.
Le moule a gateau (Model) cree a partir du plan (Schema) : chaque gateau (document) a la meme forme.
const User = mongoose.model('User', userSchema);
const alice = new User({ name: 'Alice' });
await alice.save();Cas d'usage : Creer le point d'entree pour toutes les operations sur une collection dans une app Node.js.
Fonction reutilisable qui ajoute des fonctionnalites a un schema ou a tous les schemas globalement. Permet d'encapsuler des comportements comme le soft-delete, la pagination ou l'audit.
Une extension pour navigateur : tu l'installes une fois et tous tes onglets en beneficient.
function timestampPlugin(schema) {
schema.add({ createdAt: Date, updatedAt: Date });
schema.pre('save', function() {
this.updatedAt = new Date();
});
}
mongoose.plugin(timestampPlugin);Cas d'usage : Partager des comportements communs entre plusieurs schemas sans dupliquer le code.
Methode qui remplace les ObjectId references par les documents complets de la collection liee. Equivalent d'un JOIN automatique gere par Mongoose.
Cliquer sur un lien hypertexte pour voir le contenu complet au lieu de juste le numero de reference.
const order = await Order
.findById(id)
.populate('customer', 'name email')
.populate('products');Cas d'usage : Charger les donnees liees (auteur d'un article, produits d'une commande) en une seule requete logique.
Middleware execute avant chaque appel a document.save(). Permet de modifier le document (hashing, timestamps, validation custom) avant sa persistence en base.
Le dernier controle qualite sur la chaine de montage avant de mettre le produit en boite.
schema.pre('save', function(next) {
if (!this.slug) {
this.slug = this.title
.toLowerCase()
.replace(/\s+/g, '-');
}
next();
});Cas d'usage : Generer automatiquement un slug, un hash de mot de passe ou un timestamp a chaque sauvegarde.
API chainable de Mongoose pour construire des requetes incrementalement avec where(), equals(), gt(), sort(), limit(), etc. La requete n'est executee qu'a l'appel de exec() ou await.
Un panier de courses : tu ajoutes des articles au fur et a mesure, et tu payes (exec) seulement a la fin.
const users = await User
.where('age').gte(18)
.where('status').equals('active')
.sort('-createdAt')
.limit(10)
.exec();Cas d'usage : Construire des requetes dynamiques en fonction des parametres de filtre d'une API.
Definition de la structure d'un document Mongoose : types de champs, validations, valeurs par defaut et options. Le schema est la base pour creer un Model.
Le plan d'architecte d'une maison : il definit chaque piece avant meme de poser la premiere brique.
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, unique: true },
age: { type: Number, min: 0 },
role: { type: String, enum: ['user', 'admin'] }
});Cas d'usage : Definir une structure stricte pour les documents MongoDB dans une application Node.js.
Options de configuration par champ dans un Schema : type, required, default, unique, index, lowercase, uppercase, trim, minlength, maxlength, enum, validate.
Les attributs d'un champ de formulaire HTML : requis, longueur max, format email, etc.
{
email: {
type: String,
required: [true, 'Email requis'],
lowercase: true,
trim: true,
match: /^\S+@\S+$/
}
}Cas d'usage : Definir les contraintes et transformations de chaque champ directement dans le schema.
Methode de query qui specifie les champs a inclure ou exclure du resultat. Equivalent de la projection MongoDB mais avec une syntaxe Mongoose.
Cocher les colonnes que tu veux voir dans un tableur avant d'exporter.
const user = await User
.findById(id)
.select('name email -_id');Cas d'usage : Ne retourner que les champs necessaires dans une reponse API pour reduire la bande passante.
Statics sont des methodes sur le Model (niveau classe). Methods sont des methodes sur l'instance du document. Permettent d'ajouter de la logique metier au modele.
Statics = methode de classe ('User.findByEmail'). Methods = methode d'instance ('alice.comparePassword').
// Static (sur le Model)
userSchema.statics.findByEmail = function(email) {
return this.findOne({ email });
};
// Method (sur le document)
userSchema.methods.isAdmin = function() {
return this.role === 'admin';
};Cas d'usage : Encapsuler la logique metier dans le modele au lieu de la disperser dans les services.
Option de schema qui ajoute automatiquement createdAt et updatedAt sur chaque document. updatedAt est mis a jour automatiquement a chaque modification.
Le tampon dateur du bureau de poste : chaque lettre recoit la date d'envoi et de reception.
const schema = new Schema(
{ name: String },
{ timestamps: true }
);
// Cree createdAt et updatedAt automatiquementCas d'usage : Tracer quand chaque document a ete cree et modifie pour l'audit et le debug.
Options de schema qui permettent de transformer la sortie JSON d'un document. Utile pour supprimer des champs sensibles ou renommer _id en id.
Un filtre photo automatique : chaque fois que tu exportes la photo, le filtre s'applique sans effort.
schema.set('toJSON', {
virtuals: true,
transform: (doc, ret) => {
ret.id = ret._id;
delete ret._id;
delete ret.__v;
delete ret.password;
}
});Cas d'usage : Formater automatiquement les reponses API en supprimant _id, __v et les champs sensibles.
Permet de populer une relation sans stocker de reference dans le document parent. Utilise un champ du document enfant comme foreignField pour la jointure.
Trouver tous les colis livres a une adresse sans que l'adresse ait une liste de colis.
authorSchema.virtual('books', {
ref: 'Book',
localField: '_id',
foreignField: 'author'
});
await Author.findById(id).populate('books');Cas d'usage : Creer une relation one-to-many sans tableau de references dans le parent, evitant les documents trop gros.
Proprietes calculees qui n'existent pas en base mais sont disponibles sur le document Mongoose. Definies via des getters et setters sur le schema.
L'age d'une personne : il n'est pas stocke, il est calcule a partir de la date de naissance.
userSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
const user = await User.findById(id);
console.log(user.fullName);Cas d'usage : Creer des champs derives comme fullName, age ou un URL complete sans les stocker en base.
Autres stacks