Mean 05 Mongoose Schemas
title: "Mongoose Schemas — Defining Data Models for MEAN Stack" description: "Learn Mongoose schemas for the MEAN Stack: define fields, data types, validation, default values, and indexes for MongoDB document structure." weight: 15 date: 2026-06-28 lastmod: 2026-06-28 tags: [frameworks, mean]
Mongoose schemas define the structure of documents in MongoDB, specifying fields, data types, validation rules, default values, and indexes.
What You'll Learn
You will understand how to define Mongoose schemas with various field types, validation, timestamps, and indexes.
Why It Matters
Schemas enforce data structure and validation at the application level, preventing invalid data from being saved to the database.
Real-World Use
Durga Antivirus Pro uses Mongoose schemas for threat reports with validation on severity levels, required fields, and automatic timestamps.
flowchart LR
A[Mongoose Schema] --> B[Field Definitions]
A --> C[Validation Rules]
A --> D[Timestamps]
A --> E[Indexes]
B --> F[MongoDB Document]
C --> F
D --> F
E --> F
style A fill:#4a90d9,color:#fff
Basic Schema Definition
Create a Mongoose schema for a User model.
// backend/models/User.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Name is required'],
trim: true,
minlength: [2, 'Name must be at least 2 characters'],
maxlength: [100, 'Name cannot exceed 100 characters']
},
email: {
type: String,
required: [true, 'Email is required'],
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, 'Please provide a valid email']
},
age: {
type: Number,
min: [0, 'Age cannot be negative'],
max: [150, 'Age seems unrealistic']
},
role: {
type: String,
enum: ['user', 'admin', 'moderator'],
default: 'user'
}
}, {
timestamps: true
});
Expected output: A schema for users with name, email, age, and role fields. Each field has validation rules. Timestamps add createdAt and updatedAt automatically.
Field Types
Mongoose supports multiple field types for different data.
const productSchema = new mongoose.Schema({
name: String,
price: Number,
inStock: Boolean,
tags: [String], // Array of strings
dimensions: { // Nested object
width: Number,
height: Number,
depth: Number
},
metadata: mongoose.Schema.Types.Mixed, // Any type
publishedAt: Date,
specifications: [{ // Array of nested objects
key: String,
value: String
}]
});
Expected output: A product schema with various field types including strings, numbers, booleans, arrays, nested objects, dates, and mixed types.
Custom Validation
Add custom validation logic for complex requirements.
const orderSchema = new mongoose.Schema({
items: [{
productId: { type: mongoose.Schema.Types.ObjectId, ref: 'Product' },
quantity: { type: Number, required: true, min: 1 },
price: { type: Number, required: true }
}],
status: {
type: String,
enum: ['pending', 'confirmed', 'shipped', 'delivered', 'cancelled'],
default: 'pending'
},
totalAmount: Number
});
// Custom validation
orderSchema.pre('save', function(next) {
this.totalAmount = this.items.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
next();
});
Expected output: An order schema with embedded items array and a pre-save hook that calculates the total amount automatically before saving.
Schema Indexes
Add indexes for query performance.
const postSchema = new mongoose.Schema({
title: { type: String, required: true },
slug: { type: String, required: true, unique: true },
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
tags: [{ type: String }],
status: { type: String, enum: ['draft', 'published'], index: true },
publishedAt: Date,
viewCount: { type: Number, default: 0, index: true }
});
// Compound index
postSchema.index({ status: 1, publishedAt: -1 });
postSchema.index({ tags: 1 });
Expected output: Indexes on frequently queried fields. Unique index on slug. Compound index on status + publishedAt for efficient queries.
Common Mistakes
Not defining required validations: Without required: true, fields can be missing from documents, causing undefined errors later.
Forgetting unique indexes on email fields: Without unique: true, multiple users can register with the same email.
Using overly permissive types: Using String for everything loses type safety. Use Number, Boolean, Date for appropriate fields.
Not trimming string fields: User input often has extra whitespace. Use trim: true to clean strings automatically.
Ignoring the timestamps option: Manually managing createdAt and updatedAt is error-prone. Use timestamps: true.
Practice Questions
- What does timestamps: true do in a Mongoose schema?
It automatically adds createdAt and updatedAt fields and updates them on document creation and modification.
- How do you define a unique field in a schema?
Set unique: true on the field. This creates a unique index in MongoDB that prevents duplicate values.
- What is the difference between required validation and unique index?
required prevents saving documents without the field. unique prevents duplicate values in the field across documents.
- How do you create a nested object in a schema?
Define an object with nested field definitions inside the parent field's object.
- What is a pre-save hook?
A middleware function that runs before saving a document. Used for computed fields, password hashing, or validation.
Challenge
Create schemas for a blog application: User (name, email, password), Post (title, slug, content, author, tags, status, publishedAt), and Comment (post reference, author, content, createdAt). Add appropriate validation, indexes, and timestamps.
Frequently Asked Questions
Mini Project
Create Mongoose schemas for an e-commerce application: Product (name, price, category, stock, description), Category (name, slug, description), and Review (product, user, rating, comment, createdAt).
What's Next
Learn to compile schemas into Mongoose Models and perform database operations.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro