Learn embedding vs referencing patterns, schema versioning, and designing for your access patterns.
Published April 11, 2025
Unlike relational databases, MongoDB has a flexible schema — but that flexibility demands intentional design. The golden rule: design your schema around your application's access patterns, not around the data relationships.
Embedding — store related data inside a single document
// User with embedded addresses
{
"_id": "user_1",
"name": "Alice",
"addresses": [
{ "type": "home", "city": "New York", "zip": "10001" },
{ "type": "work", "city": "Boston", "zip": "02101" }
]
}
✅ Use when: data is always read together, one-to-few relationships, no independent access to nested data.
Referencing — store a foreign key (ObjectId) and join in application code or via $lookup
// Order referencing User
{ "_id": "order_1", "userId": "user_1", "total": 99.99 }
✅ Use when: data is large/unbounded, shared across many documents, accessed independently.
| Situation | Embed | Reference |
|---|---|---|
| One-to-few | ✅ | |
| One-to-many | depends | ✅ |
| One-to-millions | ✅ | |
| Data changes frequently | ✅ | |
| Data read together 90%+ | ✅ | |
| Max document size concern (16MB) | ✅ |
Instead of one document per event (too many docs), group events into time buckets:
{
"sensorId": "sensor_42",
"date": "2024-01-15",
"readings": [
{ "time": "00:00:00", "temp": 22.1 },
{ "time": "00:01:00", "temp": 22.3 }
// ... up to 60 readings per bucket
],
"count": 60,
"avgTemp": 22.2,
"minTemp": 21.8,
"maxTemp": 22.5
}
// Most blog posts have < 100 comments → embed
// Viral posts have 10,000+ comments → use overflow flag
{
"_id": "post_1",
"title": "...",
"comments": [ /* first 100 */ ],
"hasOverflow": true // flag that more comments are in separate collection
}
Add a schemaVersion field to handle migrations gracefully:
// v1 document
{ "schemaVersion": 1, "name": "Alice Smith" }
// v2 document (migrated)
{ "schemaVersion": 2, "firstName": "Alice", "lastName": "Smith" }
// Handle both versions in application code
public User fromDocument(Document doc) {
int version = doc.getInteger("schemaVersion", 1);
if (version == 1) {
String[] parts = doc.getString("name").split(" ");
return new User(parts[0], parts[1]);
}
return new User(doc.getString("firstName"), doc.getString("lastName"));
}
MongoDB documents have a 16MB limit. For large arrays (comments, events), use referencing or the bucket pattern to stay within the limit.