Summary
MongoDB is a document-oriented NoSQL database that stores data in flexible, JSON-like BSON format. It provides horizontal scaling through sharding, high availability through replica sets, and a rich query language with aggregation framework. Key features include schema flexibility, powerful indexing, ACID transactions (v4.0+), and built-in replication. Essential for applications requiring flexible schemas, real-time analytics, content management, and handling of semi-structured data at scale.
1. MongoDB Basics
What is MongoDB?
- NoSQL database - Document-oriented, schema-less
- Stores data in BSON (Binary JSON) format
- Horizontal scaling through sharding
- High availability through replica sets
Key Concepts
| SQL | MongoDB |
|---|---|
| Database | Database |
| Table | Collection |
| Row | Document |
| Column | Field |
| Index | Index |
| JOIN | $lookup / Embedded docs |
Data Types
- String, Number (int32, int64, double)
- Boolean, Date, ObjectId
- Array, Embedded Document
- Binary Data, Null, RegEx
2. CRUD Operations
Create
// Insert one document
db.users.insertOne({ name: "John", age: 30 })
// Insert multiple documents
db.users.insertMany([
{ name: "Alice", age: 25 },
{ name: "Bob", age: 35 }
])
Read
// Find all
db.users.find()
// Find with filter
db.users.find({ age: { $gt: 25 } })
// Find one
db.users.findOne({ name: "John" })
// Projection (select fields)
db.users.find({}, { name: 1, age: 1, _id: 0 })
Update
// Update one
db.users.updateOne(
{ name: "John" },
{ $set: { age: 31 } }
)
// Update many
db.users.updateMany(
{ age: { $lt: 30 } },
{ $inc: { age: 1 } }
)
// Replace entire document
db.users.replaceOne(
{ name: "John" },
{ name: "John", age: 32, city: "NYC" }
)
Delete
// Delete one
db.users.deleteOne({ name: "John" })
// Delete many
db.users.deleteMany({ age: { $gt: 50 } })
3. Query Operators
Comparison Operators
$eq // Equal
$ne // Not equal
$gt // Greater than
$gte // Greater than or equal
$lt // Less than
$lte // Less than or equal
$in // In array
$nin // Not in array
// Example
db.users.find({ age: { $gte: 25, $lte: 35 } })
db.users.find({ status: { $in: ["active", "pending"] } })
Logical Operators
$and // AND condition
$or // OR condition
$not // NOT condition
$nor // NOR condition
// Example
db.users.find({
$and: [
{ age: { $gte: 25 } },
{ status: "active" }
]
})
db.users.find({
$or: [
{ age: { $lt: 20 } },
{ age: { $gt: 60 } }
]
})
Element Operators
$exists // Field exists
$type // Field type
// Example
db.users.find({ email: { $exists: true } })
db.users.find({ age: { $type: "number" } })
Array Operators
$all // All elements match
$elemMatch // At least one element matches
$size // Array size
// Example
db.products.find({ tags: { $all: ["red", "large"] } })
db.orders.find({ items: { $elemMatch: { price: { $gt: 100 } } } })
db.users.find({ hobbies: { $size: 3 } })
Update Operators
$set // Set field value
$unset // Remove field
$inc // Increment value
$push // Add to array
$pull // Remove from array
$addToSet // Add unique to array
$pop // Remove first/last from array
// Examples
db.users.updateOne(
{ _id: 1 },
{
$set: { status: "active" },
$inc: { loginCount: 1 },
$push: { tags: "premium" }
}
)
4. Indexes
Types of Indexes
// Single field index
db.users.createIndex({ email: 1 }) // 1 = ascending
// Compound index
db.users.createIndex({ status: 1, createdAt: -1 }) // -1 = descending
// Text index
db.articles.createIndex({ content: "text" })
// 2dsphere index (geospatial)
db.locations.createIndex({ coordinates: "2dsphere" })
// TTL index (auto-delete after time)
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
// Unique index
db.users.createIndex({ email: 1 }, { unique: true })
Index Management
// List indexes
db.users.getIndexes()
// Drop index
db.users.dropIndex({ email: 1 })
// Drop all indexes
db.users.dropIndexes()
5. Aggregation Framework
Basic Pipeline Stages
// Basic aggregation pipeline
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$customerId",
totalSpent: { $sum: "$amount" },
orderCount: { $sum: 1 }
}},
{ $sort: { totalSpent: -1 } },
{ $limit: 10 }
])
Common Pipeline Stages
$match // Filter documents
$group // Group by field(s)
$project // Shape output
$sort // Sort results
$limit // Limit results
$skip // Skip documents
$unwind // Deconstruct array
$lookup // Join collections
$count // Count documents
$facet // Multiple pipelines
// Example with $lookup (JOIN)
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
},
{ $unwind: "$customer" }
])
Aggregation Operators
// Accumulator operators (use with $group)
$sum // Sum values
$avg // Average
$min // Minimum
$max // Maximum
$first // First value
$last // Last value
$push // Create array
// Example
db.sales.aggregate([
{
$group: {
_id: "$product",
avgPrice: { $avg: "$price" },
minPrice: { $min: "$price" },
maxPrice: { $max: "$price" }
}
}
])
6. Data Modeling
Embedding vs Referencing
// Embedding (denormalized)
{
_id: 1,
name: "John",
addresses: [
{ street: "123 Main", city: "NYC" },
{ street: "456 Oak", city: "LA" }
]
}
// Referencing (normalized)
// Users collection
{ _id: 1, name: "John", addressIds: [101, 102] }
// Addresses collection
{ _id: 101, street: "123 Main", city: "NYC" }
{ _id: 102, street: "456 Oak", city: "LA" }
Schema Design Patterns
- One-to-One: Embed or reference
- One-to-Many: Embed if few, reference if many
- Many-to-Many: Use array of references
Best Practices
- Embed for data accessed together
- Reference for large/growing subdocuments
- Consider query patterns when designing
- Avoid deep nesting (max 100 levels)
7. Transactions
ACID Properties
- Atomicity: All or nothing
- Consistency: Valid state transitions
- Isolation: Concurrent operations don't interfere
- Durability: Committed data persists
Using Transactions
const session = await mongoose.startSession();
session.startTransaction();
try {
await db.accounts.updateOne(
{ _id: "A" },
{ $inc: { balance: -100 } },
{ session }
);
await db.accounts.updateOne(
{ _id: "B" },
{ $inc: { balance: 100 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
} finally {
session.endSession();
}
8. Replication & Sharding
Replica Sets
- Primary: Receives all writes
- Secondary: Replicate from primary
- Arbiter: Voting only, no data
- Minimum 3 nodes recommended
Read Preferences
primary // Default, read from primary
primaryPreferred // Primary if available
secondary // Read from secondary
secondaryPreferred
nearest // Lowest latency
Sharding
- Shard Key: Field(s) to distribute data
- Chunks: Data ranges
- Balancer: Moves chunks between shards
// Enable sharding on database
sh.enableSharding("mydb")
// Shard collection
sh.shardCollection("mydb.users", { userId: 1 })
9. Performance Optimization
Query Optimization
// Use explain() to analyze
db.users.find({ age: 30 }).explain("executionStats")
// Key metrics to check:
// - totalDocsExamined vs totalDocsReturned
// - executionTimeMillis
// - indexUsed
Query Optimization Best Practices
- Create indexes on frequently queried fields
- Use projection to limit returned fields
- Avoid $where and JavaScript execution
- Use covered queries (all fields in index)
- Limit results with pagination
- Batch operations when possible
10. Security
Authentication & Authorization
// Create user
db.createUser({
user: "appUser",
pwd: "password",
roles: [
{ role: "readWrite", db: "myapp" }
]
})
// Built-in roles
read // Read data
readWrite // Read and write
dbAdmin // Database administration
userAdmin // User administration
Security Best Practices
- Enable authentication
- Use SSL/TLS for connections
- Restrict network access
- Regular backups
- Audit logs
- Field-level encryption for sensitive data
11. Use Cases & Design Patterns
When to Use MongoDB
Good for:
- Content management systems
- Real-time analytics and IoT data
- Product catalogs with varying attributes
- Social networks and user-generated content
- Gaming leaderboards and player profiles
- Session storage and caching
Not ideal for:
- Complex multi-table transactions
- Fixed schema requirements
- Financial systems requiring strict ACID
- Heavy JOIN operations
MongoDB vs SQL Databases
CAP Theorem Implementation
- Consistency: Strong consistency with
readConcern: "majority" - Availability: High availability through replica sets
- Partition Tolerance: Automatic failover and sharding
Write Concern Levels
| Level | Description | Use Case |
|---|---|---|
w: 0 |
No acknowledgment | Fire-and-forget logging |
w: 1 |
Primary acknowledged | Default, most operations |
w: "majority" |
Majority of nodes | Critical data |
j: true |
Journaled to disk | Maximum durability |
Common Query Patterns
Time-Based Queries
// Users active in last 30 days
db.users.find({
lastLogin: {
$gte: new Date(Date.now() - 30*24*60*60*1000)
},
status: "active"
})
// Events in date range
db.events.find({
date: {
$gte: ISODate("2024-01-01"),
$lt: ISODate("2024-02-01")
}
})
Analytics Queries
// Top products by sales
db.orders.aggregate([
{ $unwind: "$items" },
{ $group: {
_id: "$items.productId",
totalRevenue: { $sum: { $multiply: ["$items.price", "$items.quantity"] } },
totalQuantity: { $sum: "$items.quantity" }
}},
{ $sort: { totalRevenue: -1 } },
{ $limit: 10 },
{ $lookup: {
from: "products",
localField: "_id",
foreignField: "_id",
as: "product"
}}
])
// User engagement metrics
db.activities.aggregate([
{ $match: {
timestamp: { $gte: new Date(Date.now() - 7*24*60*60*1000) }
}},
{ $group: {
_id: {
user: "$userId",
action: "$actionType"
},
count: { $sum: 1 }
}},
{ $group: {
_id: "$_id.user",
actions: {
$push: {
type: "$_id.action",
count: "$count"
}
},
totalActions: { $sum: "$count" }
}}
])
Working with Arrays
// Update nested array element
db.users.updateOne(
{ _id: 1, "addresses.type": "home" },
{ $set: { "addresses.$.city": "Boston" } }
)
// Add to array if not exists
db.users.updateOne(
{ _id: 1 },
{ $addToSet: { tags: "premium" } }
)
// Update all array elements
db.products.updateMany(
{},
{ $mul: { "variants.$[].price": 1.1 } } // 10% price increase
)
Advanced Schema Design Patterns
Polymorphic Pattern
// Products with different attributes
{
_id: ObjectId("..."),
type: "book",
title: "MongoDB Guide",
author: "John Doe",
isbn: "123-456",
pages: 300
}
{
_id: ObjectId("..."),
type: "electronics",
name: "Laptop",
brand: "Dell",
specs: {
cpu: "Intel i7",
ram: "16GB"
}
}
Bucket Pattern (Time Series)
// Aggregate time-series data into buckets
{
_id: ObjectId("..."),
sensorId: "sensor001",
startTime: ISODate("2024-01-01T00:00:00Z"),
endTime: ISODate("2024-01-01T01:00:00Z"),
measurements: [
{ timestamp: ISODate("2024-01-01T00:00:00Z"), temp: 22.5 },
{ timestamp: ISODate("2024-01-01T00:01:00Z"), temp: 22.7 },
// ... up to 60 measurements
],
metadata: {
avgTemp: 22.6,
maxTemp: 23.1,
minTemp: 22.3
}
}
Computed Pattern
// Pre-compute expensive calculations
{
_id: ObjectId("..."),
productId: "prod123",
ratings: [5, 4, 5, 3, 4],
// Pre-computed fields
avgRating: 4.2,
totalRatings: 5,
ratingDistribution: {
5: 2,
4: 2,
3: 1
}
}
## 12. MongoDB vs SQL Quick Reference
| Operation | SQL | MongoDB |
|-----------|-----|---------|
| Create Table/Collection | CREATE TABLE users | db.createCollection("users") |
| Insert | INSERT INTO users VALUES | db.users.insertOne({}) |
| Select All | SELECT * FROM users | db.users.find() |
| Where | WHERE age > 25 | { age: { $gt: 25 } } |
| Join | JOIN orders ON... | $lookup aggregation |
| Group By | GROUP BY status | $group aggregation |
| Order By | ORDER BY age DESC | .sort({ age: -1 }) |
| Limit | LIMIT 10 | .limit(10) |
| Update | UPDATE users SET... | db.users.updateOne() |
| Delete | DELETE FROM users | db.users.deleteOne() |
## 13. Troubleshooting & Optimization
### Common Performance Issues
#### Slow Queries
```javascript
// Analyze query performance
db.users.find({ age: { $gt: 25 } }).explain("executionStats")
// Key metrics to check:
{
executionStats: {
totalDocsExamined: 10000, // Should be close to totalReturned
totalDocsReturned: 100,
executionTimeMillis: 50,
indexesUsed: ["age_1"]
}
}
Memory Issues
// Check collection stats
db.users.stats()
// Monitor working set
db.serverStatus().wiredTiger.cache
// Limit memory usage for queries
db.adminCommand({ setParameter: 1, internalQueryExecMaxBlockingSortBytes: 33554432 })
Connection Issues
// Check current connections
db.serverStatus().connections
// Set connection pool size (Node.js example)
const options = {
maxPoolSize: 100,
minPoolSize: 10,
maxIdleTimeMS: 10000
}
Index Optimization
// Find missing indexes
db.users.aggregate([
{ $indexStats: {} },
{ $match: { "accesses.ops": { $lt: 100 } } }
])
// Remove unused indexes
db.users.dropIndex({ field: 1 })
// Create compound index for common queries
db.orders.createIndex({ userId: 1, status: 1, createdAt: -1 })
Monitoring Commands
// Real-time operations
db.currentOp()
// Kill long-running operation
db.killOp(opId)
// Database profiler
db.setProfilingLevel(1, { slowms: 100 })
db.system.profile.find().limit(5).sort({ ts: -1 })
14. Key Takeaways
Architecture & Design
- Document model provides schema flexibility
- Horizontal scaling through automatic sharding
- High availability via replica sets with automatic failover
- Choose embedding vs referencing based on access patterns
Performance & Operations
- Indexes are crucial - Monitor and optimize regularly
- Aggregation framework enables complex analytics
- Use projections to reduce network overhead
- Write concerns balance durability vs performance
Modern Features
- ACID transactions for multi-document operations (v4.0+)
- Change streams for real-time data pipelines
- Schema validation for data integrity when needed
- Time series collections optimized for IoT data (v5.0+)
Best Practices Summary
- Design schema based on query patterns
- Use appropriate indexes but avoid over-indexing
- Implement proper error handling and retries
- Monitor performance metrics regularly
- Plan sharding strategy early for large datasets
- Use connection pooling effectively
- Implement proper backup and disaster recovery