Introduction
—Cover
00Overview
Core Modules
01Intro to MongoDB
02Fundamentals
03CRUD Operations
04Querying Data
05Indexes
06Schema Design
07Aggregation
08Advanced Features
09Node.js & Mongoose
Production
10Security
11Backup & Deploy
12Scaling
Projects
13Mini Projects
⚡Cheat Sheet
M
Complete Engineering Guide
MongoDB
From Zero to Production
From Zero to Production
A practical, project-based course covering every aspect of MongoDB — from first document to sharded, replicated, production-ready systems.
13 Modules
3 Hands-On Projects
Production Best Practices
Node.js + Mongoose
MongoDB Atlas
Course Map
What You'll Master
13 modules covering every layer of MongoDB engineering — progressively building from fundamentals to distributed systems.
13
Modules
3
Projects
50+
Code Examples
∞
Scalability
MOD 01–02
Foundations
NoSQLBSONDocuments
MOD 03–04
Data Operations
CRUDQueryingOperators
MOD 05–06
Performance
IndexesSchema Design
MOD 07–08
Power Features
AggregationTransactions
MOD 09
Node.js Integration
MongooseModelsHooks
MOD 10–12
Production
SecurityBackupScaling
Module 01
Introduction to MongoDB
What MongoDB is, how it differs from SQL, and getting your environment running.
Relational (SQL)
- Data in rows & columns (tables)
- Fixed schema — ALTER TABLE to change
- JOINs across normalized tables
- Vertical scaling (bigger server)
- SQL query language
MongoDB (NoSQL)
- Data in flexible JSON-like documents
- Dynamic schema — add fields freely
- Embedded docs or $lookup
- Horizontal scaling (sharding)
- MQL — MongoDB Query Language
Quick Install (Docker)
bash
# Pull MongoDB 7.0 with persistent storage
docker run -d \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secret \
-v mongodb_data:/data/db \
mongo:7.0
# Connect with mongosh
mongosh 'mongodb://admin:secret@localhost:27017'
Best Use Cases
Content Management
Flexible document structures for articles, media, and user-generated content.
E-Commerce
Variable product attributes per category — no rigid table schema needed.
Real-Time Analytics
Fast writes and powerful aggregation pipelines for live dashboards.
IoT / Time-Series
High-throughput sensor data ingestion with time-series collections.
Microservices
Each service owns its own database with schema freedom per domain.
Gaming & Mobile
User profiles, sessions, leaderboards — fast reads, flexible structure.
Module 02
MongoDB Fundamentals
Databases, collections, documents, BSON, and core data modeling concepts.
Database
A logical container for collections. One MongoDB server can host many databases. Created on first write.
Collection
A group of documents — like a SQL table, but without a fixed schema. Auto-created on first insert.
Document
The fundamental data unit. BSON-encoded object with up to 16 MB. Every doc has a unique _id.
A MongoDB Document
mongosh
{
"_id": ObjectId("64a7f3b2c1d2e3f4a5b6c7d8"),
"name": "Alice Nakamura",
"email": "alice@example.com",
"age": 29,
"address": {
"city": "Kigali",
"country": "Rwanda"
},
"tags": ["developer", "nodejs", "mongodb"],
"createdAt": ISODate("2024-01-15T08:30:00Z")
}
BSON vs JSON
MongoDB stores data as BSON (Binary JSON) — a superset of JSON that adds richer types: ObjectId, Date, Decimal128, Binary, Int32/64. You interact with it as JSON; MongoDB handles the conversion.
Essential Shell Commands
mongosh
show dbs // list databases
use shopDB // switch / create db
show collections // list collections
db.createCollection('products') // explicit creation
db.dropDatabase() // delete current db
Module 03
CRUD Operations
Create, Read, Update, Delete — the four pillars of data manipulation in MongoDB.
CREATE — insertOne / insertMany
mongosh
db.products.insertOne({
name: 'Laptop Pro',
price: 1299,
stock: 45
})
db.products.insertMany([
{ name: 'Mouse', price: 29 },
{ name: 'Keyboard', price: 149 }
], { ordered: false })
READ — find / findOne
mongosh
db.products.find()
db.products.findOne(
{ name: 'Laptop Pro' }
)
// Projection: name & price only
db.products.find(
{ category: 'Electronics' },
{ name: 1, price: 1, _id: 0 }
)
UPDATE — updateOne / updateMany
mongosh
db.products.updateOne(
{ name: 'Mouse' },
{ $set: { price: 34.99 },
$inc: { stock: 50 } }
)
// 10% price increase for all Furniture
db.products.updateMany(
{ category: 'Furniture' },
{ $mul: { price: 1.10 } }
)
DELETE — deleteOne / deleteMany
mongosh
db.products.deleteOne(
{ name: 'Notebook A5' }
)
db.products.deleteMany(
{ stock: 0 }
)
// Always test filter with find() first!
Key Update Operators
| Operator | Action | Example |
|---|---|---|
$set | Set or add a field value | { $set: { price: 99 } } |
$inc | Increment a number | { $inc: { stock: -1 } } |
$mul | Multiply a number | { $mul: { price: 0.9 } } |
$push | Append to array | { $push: { tags: 'sale' } } |
$pull | Remove from array | { $pull: { tags: 'old' } } |
$unset | Remove a field | { $unset: { oldField: '' } } |
Module 04
Querying Data
Comparison operators, logical operators, projection, sorting, and array queries.
Comparison Operators
mongosh
// Greater than / less than
db.products.find({
price: { $gt: 100, $lte: 500 }
})
// In a set of values
db.products.find({
category: { $in: ['Electronics',
'Furniture'] }
})
// Not equal
db.products.find({
status: { $ne: 'discontinued' }
})
Logical Operators
mongosh
// $and — all conditions match
db.products.find({ $and: [
{ category: 'Electronics' },
{ price: { $lt: 200 } },
{ rating: { $gte: 4.5 } }
]})
// $or — any condition matches
db.products.find({ $or: [
{ price: { $lt: 30 } },
{ stock: { $gt: 100 } }
]})
Sorting, Limiting & Pagination
mongosh
// Sort by price descending, then name ascending
db.products.find().sort({ price: -1, name: 1 })
// Pagination — page 3 with page size 10
db.products.find()
.sort({ createdAt: -1 })
.skip(20)
.limit(10)
// Count matching docs
db.products.countDocuments({ category: 'Electronics' })
Array & Nested Queries
mongosh
// Array contains 'gaming'
db.products.find({ tags: 'gaming' })
// $elemMatch — array element satisfies multiple conditions
db.orders.find({
items: { $elemMatch: { qty: { $gte: 2 }, price: { $lt: 100 } } }
})
// Nested field (dot notation)
db.users.find({ 'address.city': 'Kigali' })
Module 05
Indexes & Performance
Understanding indexes, when to use them, and how to make queries lightning fast.
Without Index (COLLSCAN)
- MongoDB reads EVERY document
- 10,000 docs → 10,000 reads
- O(n) time complexity
- Terrible for large collections
With Index (IXSCAN)
- MongoDB traverses B-tree structure
- 10,000 docs → reads only matches
- O(log n) time complexity
- Essential for production queries
mongosh
// Create a single-field index
db.users.createIndex({ email: 1 }, { unique: true })
// Compound index — follow ESR rule (Equality → Sort → Range)
db.products.createIndex({ category: 1, price: -1 })
// TTL index — auto-expire session docs after 1 hour
db.sessions.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600 }
)
// Text index for full-text search
db.products.createIndex({ name: 'text', description: 'text' })
db.products.find({ $text: { $search: 'mechanical keyboard' } })
// Analyze query with explain
db.products.find({ category: 'Electronics' })
.explain('executionStats')
ESR Rule
For compound indexes: Equality fields first, Sort fields second, Range fields last. This rule maximizes how many pipeline stages can use your index.
Index Types
| Type | Use Case |
|---|---|
| Single Field | Queries on one field — { email: 1 } |
| Compound | Multi-field queries — { category: 1, price: -1 } |
| Unique | Enforce uniqueness — { unique: true } |
| TTL | Auto-expire documents — sessions, logs, caches |
| Text | Full-text search on string fields |
| 2dsphere | Geospatial queries — { location: '2dsphere' } |
| Sparse | Index only docs where field exists |
Module 06
Schema Design & Data Modeling
The most impactful decisions in MongoDB: when to embed, when to reference, and how to model relationships.
| Factor | → Embed | → Reference |
|---|---|---|
| Data always read together | YES | |
| Data updated independently | YES | |
| Data grows without bound | YES | |
| 1:1 or 1:few relationship | YES | |
| 1:many (large many) | YES | |
| Many:many | YES |
Embedding (Denormalized)
mongosh
{
_id: ObjectId("..."),
orderNumber: "ORD-001",
customer: { // embedded
name: "Bob Smith",
email: "bob@..."
},
items: [ // embedded array
{ product: "Laptop", qty: 1, price: 1200 }
]
}
Referencing (Normalized)
mongosh
// Products collection
{ _id: ObjectId("prod001"),
name: "Laptop", stock: 50 }
// Orders — reference by ID
{ _id: ObjectId("ord001"),
items: [{
productId: ObjectId("prod001"),
qty: 1
}]
}
Golden Rule
Data that is accessed together should be stored together. MongoDB's power comes from colocating related data to avoid expensive joins — but only when the relationship is bounded and stable.
Module 07
Aggregation Framework
MongoDB's most powerful feature — a pipeline of data transformation stages for analytics and reporting.
The Pipeline
$match
→
$unwind
→
$group
→
$sort
→
$project
→
Result
Sales Report by Category
mongosh — aggregation pipeline
db.orders.aggregate([
// Stage 1: Only completed orders
{ $match: { status: 'completed' } },
// Stage 2: Flatten the items array
{ $unwind: '$items' },
// Stage 3: Group by category, sum revenue
{ $group: {
_id: '$items.category',
totalRevenue: { $sum: { $multiply: ['$items.price', '$items.qty'] } },
orderCount: { $sum: 1 }
}},
// Stage 4: Sort by revenue
{ $sort: { totalRevenue: -1 } },
// Stage 5: Rename and format fields
{ $project: {
_id: 0, category: '$_id',
totalRevenue: { $round: ['$totalRevenue', 2] },
orderCount: 1
}}
])
Key Aggregation Operators
| Operator | Stage | Description |
|---|---|---|
$sum | $group | Sum values across grouped documents |
$avg | $group | Calculate average of a field |
$lookup | standalone | LEFT JOIN with another collection |
$facet | standalone | Run multiple pipelines in parallel |
$addFields | standalone | Add computed fields without removing existing |
Module 08
Advanced MongoDB Features
Transactions, schema validation, change streams, and geospatial queries.
Multi-Document Transactions
Atomic operations across multiple documents — essential for financial transfers and complex workflows.
mongosh
const session = db.getMongo()
.startSession()
session.startTransaction()
try {
accounts.updateOne(
{ _id: 'acc001' },
{ $inc: { balance: -500 } },
{ session }
)
accounts.updateOne(
{ _id: 'acc002' },
{ $inc: { balance: 500 } },
{ session }
)
session.commitTransaction()
} catch (e) {
session.abortTransaction()
}
Change Streams
Real-time notifications of data changes — no polling. Foundation for live dashboards and event-driven systems.
mongosh
// Watch with filter
const pipeline = [{
$match: {
operationType: 'update',
'updateDescription'
'.updatedFields.status': 'completed'
}
}]
db.orders
.watch(pipeline)
.forEach(change => {
printjson(change)
})
Schema Validation
mongosh
db.createCollection('users', {
validator: { $jsonSchema: {
bsonType: 'object',
required: ['name', 'email', 'role'],
properties: {
email: { bsonType: 'string', pattern: '^\\S+@\\S+\\.\\S+$' },
age: { bsonType: 'int', minimum: 18, maximum: 120 },
role: { enum: ['admin', 'customer', 'vendor'] }
}
}},
validationAction: 'error' // reject invalid docs
})
Module 09
Node.js & Mongoose
Connecting MongoDB to your Node.js application using Mongoose ODM — models, schemas, hooks, and production patterns.
Application
Express.js
REST Routes
Controllers
ODM Layer
Mongoose
Models
Schemas
Middleware/Hooks
Database
MongoDB
Collections
Indexes
Mongoose Model Definition
models/User.js
const userSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
email: { type: String, unique: true, lowercase: true },
role: { type: String,
enum: ['admin', 'customer'],
default: 'customer' }
}, { timestamps: true })
// Pre-save hook — hash password
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next()
this.password = await bcrypt.hash(this.password, 12)
next()
})
module.exports = mongoose.model('User', userSchema)
CRUD via Mongoose
Node.js
// CREATE
await User.create({ name: 'Alice', ... })
// READ with filtering & projection
await User.find({ role: 'customer' })
.select('name email')
.sort({ createdAt: -1 })
.limit(20)
// UPDATE — return updated doc
await User.findByIdAndUpdate(
userId,
{ $set: { bio: 'Developer' } },
{ new: true, runValidators: true }
)
// DELETE
await User.findByIdAndDelete(userId)
Module 10
Authentication & Security
Securing your MongoDB deployment — users, roles, network security, and preventing injection attacks.
Built-in Roles
| Role | Permissions |
|---|---|
read | Read non-system collections |
readWrite | Read + write collections |
dbAdmin | Admin tasks (indexes, stats) |
userAdmin | Create & modify users |
dbOwner | Full control of database |
root | Superuser — use sparingly |
Security Checklist
- Enable authentication in mongod.conf
- Bind to localhost or private IP only
- Enable TLS/SSL in production
- Use firewall to restrict port 27017
- Store credentials in env vars only
- Enable audit logging
- Use least-privilege user per service
- Rotate passwords regularly
Preventing NoSQL Injection
Vulnerable Pattern
Node.js — DO NOT DO THIS
// Attacker sends: { $gt: '' }
db.users.findOne({
email: req.body.email,
password: req.body.password
})
Safe Pattern
Node.js — CORRECT
// Find by email, verify via bcrypt
const user = await User
.findOne({ email: req.body.email })
.select('+password')
if (!user || !await user
.comparePassword(req.body.password)) {
return res.status(401).json({ error: 'Unauthorized' })
}
Module 11
Backup & Deployment
Local backups with mongodump, and deploying to MongoDB Atlas for production cloud hosting.
mongodump / mongorestore
bash
# Full backup with compression
mongodump \
--uri='mongodb://localhost/myapp' \
--gzip \
--archive=/backups/myapp_$(date +%Y%m%d).gz
# Restore from archive
mongorestore \
--gzip \
--archive=/backups/myapp_20240115.gz
# Restore to a different DB name
mongorestore \
--nsFrom='myapp.*' \
--nsTo='myapp_staging.*' \
/backups/20240115
MongoDB Atlas Setup
- Create free account at mongodb.com/atlas
- Create a Project and Cluster (M0 Free Tier)
- Configure Network Access (IP whitelist)
- Create a Database User with readWrite role
- Copy connection string from Connect dialog
- Connect via mongosh or Mongoose
Node.js .env
MONGO_URI=mongodb+srv://appUser:<pass>
@cluster0.abc123.mongodb.net/myapp
?retryWrites=true&w=majority
Atlas Backup Tiers
Atlas M10+ clusters include continuous cloud backup with point-in-time restore. Free tier (M0) has no automated backups — use mongodump on a schedule for non-production environments.
Module 12
Performance & Scaling
Replica sets for high availability and sharding for horizontal scale — production-grade MongoDB architecture.
Replica Set (HA)
- 1 Primary + 2+ Secondaries
- Automatic failover in ~10 seconds
- Read from secondaries to scale reads
- Write concern: w:majority for safety
- Minimum 3 nodes recommended
mongosh
rs.initiate({
_id: 'rs0',
members: [
{ _id: 0, host: 'host1:27017' },
{ _id: 1, host: 'host2:27017' },
{ _id: 2, host: 'host3:27017' }
]
})
rs.status()
Sharding (Horizontal Scale)
- Data distributed across shard nodes
- mongos router directs queries
- Config servers store cluster metadata
- Shard key choice is critical
- Each shard is a replica set
mongosh
sh.enableSharding('myapp')
// Hashed key — even distribution
sh.shardCollection(
'myapp.orders',
{ _id: 'hashed' }
)
sh.status()
Shard Key Warning
A poor shard key causes write hotspots — all traffic hits one shard. Avoid monotonically increasing values (timestamps, auto-increment IDs) for write-heavy workloads. Use hashed shard keys or high-cardinality compound keys.
Module 13
Mini Projects
Three hands-on projects to cement your MongoDB skills — beginner to advanced.
Beginner
User Database
Build a user management system with registration, profile updates, role-based access, and basic querying. Reinforces CRUD, indexes, and schema validation.
insertMany
createIndex unique
$jsonSchema
find + sort
Intermediate
Blog System
A blogging platform with posts, embedded comments, tags, and author references. Covers data modeling decisions, full-text search, and aggregation for analytics (top posts, author leaderboard).
Embedding vs Referencing
Text Index
$lookup
$facet analytics
Advanced
E-Commerce Backend
Full backend with users, product catalogue, shopping carts (TTL), orders, payments, and a real-time dashboard. Atomic order placement with transactions, live tracking via change streams, and revenue analytics pipeline.
Transactions
Change Streams
TTL Index
$facet Dashboard
Mongoose ODM
Node.js
Reference Card
Quick Cheat Sheet
The most-used commands and operators in one place.
Essential Shell Commands
| Command | Action |
|---|---|
show dbs | List databases |
use <db> | Switch database |
show collections | List collections |
db.col.find().pretty() | Display all docs |
db.col.countDocuments() | Count docs |
db.col.createIndex() | Create index |
db.col.explain() | Analyze query plan |
rs.status() | Replica set status |
sh.status() | Shard cluster status |
Aggregation Stages
| Stage | Quick Example |
|---|---|
$match | { status: 'active' } |
$group | { _id: '$city', n: {$sum:1} } |
$sort | { total: -1 } |
$project | { name:1, total:1, _id:0 } |
$lookup | JOIN another collection |
$unwind | Flatten array field |
$limit | { $limit: 10 } |
$addFields | Add computed fields |
$facet | Multi-pipeline parallel |
Update Operators Reference
$set / $unset
Set a field value or remove a field entirely.
$inc / $mul
Increment a number or multiply it (e.g. 10% discount with $mul: 0.9).
$push / $pull
Add to or remove from an array. Use $addToSet for uniqueness.