MongoDB Schema Design: Embed or Reference?
"Schemaless" doesn't mean "no design". In MongoDB, schema design starts from one question: what does the application read together?
Embed when data is read together and owned by the parent
{
"_id": "ord_42",
"customerId": 7,
"status": "paid",
"shippingAddress": { "city": "Pune", "pin": "411001" },
"items": [
{ "sku": "MUG-01", "name": "Mug", "qty": 2, "price": 349 },
{ "sku": "TEE-M", "name": "T-shirt", "qty": 1, "price": 799 }
]
}
One read returns the whole order. Item names and prices are copied at purchase time, which is correct: an order shouldn't change if the product is renamed later.
Reference when data is shared, large or unbounded
// posts
{ "_id": "post_1", "title": "Hello", "authorId": "user_7" }
// comments: one document each, referencing the post
{ "_id": "c_1", "postId": "post_1", "text": "Great article!", "createdAt": "2026-10-10T09:00:00Z" }
A popular post could get thousands of comments; embedding them would make the document huge (documents have a 16 MB limit) and slow to update.
Rules of thumb
- One-to-few (addresses, phone numbers): embed.
- One-to-many (hundreds): embed IDs or reference from the child, depending on the queries.
- One-to-squillions (logs, comments, events): reference from the child.
- Many-to-many: arrays of IDs on one or both sides.
- Data changed independently and often: reference it to avoid updating many copies.
Useful patterns
- Subset: embed the 5 most recent reviews in the product; store all reviews separately.
- Extended reference: copy a few frequently needed fields (author name) alongside the reference.
- Computed: keep counters like
commentCountupdated with$incinstead of counting on every read. - Bucket: group time-series readings into one document per sensor per hour.
Duplication is a deliberate trade-off in MongoDB: faster reads in exchange for more work when the duplicated data changes.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.