Mongoose Models, Validation and Middleware
MongoDB itself is flexible about document shape. Mongoose adds schemas, validation, defaults and helpers on top of the official driver, which brings structure to application code.
Defining a model
import mongoose from 'mongoose';
await mongoose.connect(process.env.MONGODB_URI);
const productSchema = new mongoose.Schema(
{
name: { type: String, required: true, trim: true, maxlength: 200 },
slug: { type: String, required: true, unique: true, lowercase: true },
price: { type: Number, required: true, min: 0 },
category: { type: String, enum: ['books', 'electronics', 'clothing'], index: true },
tags: [String],
seller: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
},
{ timestamps: true } // adds createdAt and updatedAt
);
productSchema.index({ category: 1, price: 1 });
export const Product = mongoose.model('Product', productSchema);
Validation
try {
await Product.create({ name: '', price: -5, slug: 'x', seller: userId });
} catch (err) {
if (err instanceof mongoose.Error.ValidationError) {
console.log(Object.keys(err.errors)); // ['name', 'price']
}
}
Validators run on create and save. For updateOne and similar, pass { runValidators: true }.
populate: follow references
const product = await Product.findOne({ slug: 'red-mug' }).populate('seller', 'name email');
console.log(product.seller.name);
populate runs an extra query per referenced path; use it deliberately on lists.
Middleware (hooks)
productSchema.pre('validate', function () {
if (!this.slug && this.name) this.slug = slugify(this.name);
});
lean() for read-heavy endpoints
const products = await Product.find({ category: 'books' }).sort({ price: 1 }).limit(20).lean();
// plain objects: much faster and lighter than full Mongoose documents
Mongoose or the raw driver?
- Mongoose: application code where schemas, validation and hooks keep data consistent.
- Native driver: maximum performance, simple data access layers, or when you'd rather validate with Zod at the API boundary.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.