How do you model a one-to-many relationship in MongoDB?
Learn how to model one-to-many relationships in MongoDB with embedding vs referencing, when to use each, the 16MB limit, and joining with $lookup.
Expected Interview Answer
You model a one-to-many relationship in MongoDB either by embedding the many-side documents inside the one-side document, or by referencing them with a stored parent id in a separate collection — the choice depends on access patterns, cardinality, and document growth.
Embedding stores the child documents as an array inside the parent, giving single-read locality and atomic updates, and it fits bounded, tightly-coupled data (a post and its few tags). Referencing keeps children in their own collection with a field pointing back to the parent's _id, which suits unbounded or independently-queried data (a customer and thousands of orders) and avoids the 16MB document limit. A common rule of thumb is embed for "few", reference for "many" or "unbounded", and sometimes combine both.
- Embedding gives fast single-document reads and atomic writes
- Referencing avoids unbounded document growth and the 16MB limit
- You can query child data independently when referenced
- Model matches real access patterns instead of forcing joins
- Flexibility to combine embedding and referencing (hybrid) when needed
AI Mentor Explanation
Modeling a team and its players is like choosing whether to write each player's stats directly onto the team sheet (embedding) or to keep a separate player register that notes which team each belongs to (referencing). A short XI fits neatly on the sheet, but a franchise's full academy of hundreds is better kept in its own register you can query on its own.
Step-by-Step Explanation
Step 1
Analyze access patterns
Ask how the data is read and written together — if children are almost always fetched with the parent, lean toward embedding.
Step 2
Estimate cardinality
Few and bounded children favor embedding; many or unbounded children favor referencing to avoid document bloat.
Step 3
Check document growth
Ensure the parent document plus its embedded array stays well under the 16MB BSON limit and avoids constant array growth.
Step 4
Embed for locality
Store children as an array in the parent for single-read access and atomic updates when they are tightly coupled.
Step 5
Reference for scale
Put children in their own collection with a parentId field, and query with a filter or $lookup when you need to join.
Step 6
Consider a hybrid
Embed a summary or the most recent few children in the parent while keeping the full set in a referenced collection.
What Interviewer Expects
- Knowing both embedding and referencing approaches
- Choosing based on access patterns, cardinality, and growth
- Awareness of the 16MB document size limit
- Understanding $lookup for joining referenced collections
- Recognizing the hybrid pattern for large, growing relationships
Common Mistakes
- Always embedding regardless of unbounded growth
- Assuming MongoDB cannot model relationships at all
- Ignoring the 16MB document limit when embedding arrays
- Over-normalizing like a relational schema and losing read locality
- Forgetting to index the parentId field on referenced children
Best Answer (HR Friendly)
“In MongoDB you have two main choices for a one-to-many link: put the many items directly inside the parent document (embedding) when there are only a few, or keep them in a separate collection that points back to the parent (referencing) when there are many. You pick based on how the data is used and how large it can grow.”
Code Example
// A blog post embeds its (few) comments
await db.collection('posts').insertOne({
title: 'Modeling data in MongoDB',
comments: [
{ user: 'Ada', text: 'Great post' },
{ user: 'Lin', text: 'Very helpful' }
]
});// Orders live in their own collection, pointing at the customer
await db.collection('orders').insertOne({ customerId: custId, total: 99 });
await db.collection('orders').createIndex({ customerId: 1 });
// Join a customer with all their orders
const rows = await db.collection('customers').aggregate([
{ $match: { _id: custId } },
{ $lookup: {
from: 'orders',
localField: '_id',
foreignField: 'customerId',
as: 'orders'
} }
]).toArray();Follow-up Questions
- When would you choose embedding over referencing?
- What is the 16MB document limit and how does it affect embedding?
- How does $lookup work and what are its performance costs?
- What is the extended reference / hybrid pattern?
- How would you model a many-to-many relationship in MongoDB?
MCQ Practice
1. Which factor most favors embedding the many-side documents?
Embedding suits few, bounded children that are almost always accessed together with the parent, giving single-read locality.
2. Why might you reference instead of embed a one-to-many relationship?
Referencing keeps children in a separate collection, avoiding unbounded parent growth and the 16MB limit while allowing independent queries.
3. What operator joins a referenced collection in an aggregation?
$lookup performs a left outer join to another collection within an aggregation pipeline.
Flash Cards
Two ways to model one-to-many in MongoDB? — Embedding the children in the parent, or referencing them in a separate collection via a parentId.
When to embed? — When children are few, bounded, tightly coupled, and usually read with the parent.
When to reference? — When children are many or unbounded, queried independently, or would push the parent toward the 16MB limit.
How do you join referenced collections? — Use $lookup in an aggregation pipeline to left-outer-join by matching fields.
What is the hybrid pattern? — Embed a summary or the latest few children in the parent while keeping the full set in a referenced collection.