MongoDB and Mongoose: Schema-First Design
While MongoDB is "schemaless", professional MERN apps use Mongoose to enforce a schema at the application level. This ensures data integrity and provides a clean API for CRUD operations.
Defining Models and Schemas
A Schema defines the structure of your documents. A Model is a wrapper around the schema that provides methods like .find(), .create(), etc.
javascript codeconst mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Please provide a name'] }, email: { type: String, unique: true, lowercase: true }, role: { type: String, enum: ['user', 'admin'], default: 'user' }, createdAt: { type: Date, default: Date.now } }); const User = mongoose.model('User', userSchema);
Mongoose Middlewares (Hooks)
Middlewares allow you to run logic before or after certain actions (e.g., hashing a password before saving).
javascript codeuserSchema.pre('save', async function(next) { if (!this.isModified('password')) return next(); this.password = await bcrypt.hash(this.password, 12); next(); });
Advanced Population (Joining)
Mongoose provides .populate() to handle references between collections, making it feel like a relational join.
javascript codeconst posts = await Post.find().populate('author', 'name email');
Virtuals
Virtuals are fields that are not stored in the database but can be accessed like regular fields. Perfect for fields like fullName (combining firstName and lastName).