1 / 16
M
Complete Engineering Guide
MongoDB
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

OperatorActionExample
$setSet or add a field value{ $set: { price: 99 } }
$incIncrement a number{ $inc: { stock: -1 } }
$mulMultiply a number{ $mul: { price: 0.9 } }
$pushAppend to array{ $push: { tags: 'sale' } }
$pullRemove from array{ $pull: { tags: 'old' } }
$unsetRemove 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

TypeUse Case
Single FieldQueries on one field — { email: 1 }
CompoundMulti-field queries — { category: 1, price: -1 }
UniqueEnforce uniqueness — { unique: true }
TTLAuto-expire documents — sessions, logs, caches
TextFull-text search on string fields
2dsphereGeospatial queries — { location: '2dsphere' }
SparseIndex 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 togetherYES
Data updated independentlyYES
Data grows without boundYES
1:1 or 1:few relationshipYES
1:many (large many)YES
Many:manyYES
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

OperatorStageDescription
$sum$groupSum values across grouped documents
$avg$groupCalculate average of a field
$lookupstandaloneLEFT JOIN with another collection
$facetstandaloneRun multiple pipelines in parallel
$addFieldsstandaloneAdd 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
RolePermissions
readRead non-system collections
readWriteRead + write collections
dbAdminAdmin tasks (indexes, stats)
userAdminCreate & modify users
dbOwnerFull control of database
rootSuperuser — 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
  1. Create free account at mongodb.com/atlas
  2. Create a Project and Cluster (M0 Free Tier)
  3. Configure Network Access (IP whitelist)
  4. Create a Database User with readWrite role
  5. Copy connection string from Connect dialog
  6. 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

CommandAction
show dbsList databases
use <db>Switch database
show collectionsList 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

StageQuick Example
$match{ status: 'active' }
$group{ _id: '$city', n: {$sum:1} }
$sort{ total: -1 }
$project{ name:1, total:1, _id:0 }
$lookupJOIN another collection
$unwindFlatten array field
$limit{ $limit: 10 }
$addFieldsAdd computed fields
$facetMulti-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.
Navigate: or click sidebar