Extended Reference Pattern
When documents reference another collection, embed the most frequently accessed fields from the referenced document directly in the referencing document. This eliminates the need for a second lookup for those fields.
{ orderId: "ORD-001", customerId: ObjectId("...") }
db.customers.findOne({ _id: ObjectId("...") })
{
orderId: "ORD-001",
customerId: ObjectId("..."),
customer: {
name: "Alice Johnson",
email: "alice@example.com"
},
total: 89.97
}
Computed / Pre-calculated Pattern
Instead of counting or summing at read time, maintain the aggregate value in the document and update it on write. Read operations are O(1); aggregation cost is paid once per write instead of on every read.
db.likes.countDocuments({ postId: ObjectId("...") })
{
_id: ObjectId("..."),
title: "MongoDB Schema Design",
likeCount: 1247,
viewCount: 58300
}
db.posts.updateOne(
{ _id: postId },
{ $inc: { likeCount: 1 } }
)
Subset Pattern
For one-to-many relationships where you need to display only the N most recent or relevant items, embed the latest N items in the parent document and keep the full list in a child collection.
{
_id: ObjectId("..."),
name: "Wireless Headphones",
avgRating: 4.3,
reviewCount: 2847,
recentReviews: [
{ user: "Alice", rating: 5, text: "Excellent sound quality" },
{ user: "Bob", rating: 4, text: "Good value for money" },
]
}
db.products.updateOne(
{ _id: productId },
{
$push: {
recentReviews: {
$each: [newReview],
$sort: { date: -1 },
$slice: 5
}
},
$inc: { reviewCount: 1 },
$set: { avgRating: newAverage }
}
)
Bucket Pattern
For time-series data with high write throughput (IoT sensors, logs, metrics), group time-adjacent readings into a single "bucket" document instead of one document per reading. Dramatically reduces document count and index size.
{ sensorId: "S1", timestamp: ISODate("..."), temp: 22.4 }
{ sensorId: "S1", timestamp: ISODate("..."), temp: 22.5 }
{
sensorId: "S1",
hour: ISODate("2024-03-01T10:00:00Z"),
count: 60,
readings: [
{ minute: 0, temp: 22.4 },
{ minute: 1, temp: 22.5 },
],
stats: {
min: 22.1,
max: 23.0,
avg: 22.6
}
}
db.sensor_data.updateOne(
{ sensorId: "S1", hour: currentHour, count: { $lt: 60 } },
{ $push: { readings: newReading }, $inc: { count: 1 } },
{ upsert: true }
)
NOTE
MongoDB has a native Time Series Collection type (v5.0+) which internally applies the bucket pattern automatically — preferred over manual bucket implementation for new IoT/metrics projects. Use db.createCollection("sensor_data", { timeseries: { timeField: "timestamp", metaField: "sensorId" } }).