MongoDb Schema Design
MongoDB, known for its flexible and "schema-less" design, lets you store records as documents made up of key/value pairs in collections. These documents can differ in fields and data types, providing a flexible approach to data modeling. You can enhance this flexibility by embedding sub-documents to manage relationships effectively.
While this adaptability is a strength, it introduces complexities, especially when managing relationships like one-to-many and many-to-many in a denormalized structure. Here, we'll dissect different ways to manage these relationships in MongoDB, explain embedding versus referencing, and look at practical examples and best practices for efficient data modeling.
Key Takeaways
- MongoDB's flexible structure complicates relationship management, leading to considerations between embedding and referencing.
- Cardinality, or the count of possible relationships, greatly influences schema design choices.
- Different use cases—one-to-few, one-to-many, one-to-infinity—require tailored approaches for optimal efficiency.
- Practical schema design must consider the nature of queries and the frequency of data updates.
Preface: Understanding Cardinality
Transitioning to MongoDB from traditional RDBMS like MySQL or Postgres means a shift. While RDBMS emphasize relationships between tables, MongoDB represents related data as attributes or embedded structures within documents.
Consider a user-post relationship. A relational database might model this with separate tables and foreign keys:
User Table
id, name, email, createdAt, updatedAt
112, Sam, sam@gmail.com, 2017-12-01, 2017-12-01
Post Table
id, title, location, user_id, createdAt, updatedAt
234, "favorite pizza", "Los Angeles", 112, 2017-04-06, 2017-05-02
432, "need a break?", "Sacramento", 112, 2017-04-06, 2017-05-02
In MongoDB, this relationship can be embedded directly in a User document:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01",
posts: [
{title: "favorite pizza", location: "Los Angeles"},
{title: "need a break?", location: "Sacramento"}
]
}
Embedding posts avoids joins and can speed up lookups as a user and their posts are retrieved in a single query. However, the potential issue arises if a user has numerous posts, risking hitting MongoDB's 16 MB document size limit. In such cases, referencing documents becomes necessary:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01",
posts: [234, 432]
}
Post Documents
{
id: 234,
title: "favorite pizza",
location: "Los Angeles"
}
{
id: 432,
title: "need a break?",
location: "Sacramento"
}
Referencing from a separate Post collection better accommodates numerous entries. Decisions to embed or reference are fundamental in MongoDB schema design. High cardinality relationships often favor separate collections, which enables easier independent querying of data.
Modeling Relationships
MongoDB allows for diverse data modeling strategies. Generally, a good schema will mix embedding and referencing based on relationship cardinality and application query patterns. Let's explore several relationship strategies, their examples, and pros and cons.
MongoDB One-to-Few
In one-to-few cases, embedding works best. Take users with a limited set of roles:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01",
roles: [
{title: "admin", canEdit: true},
{title: "customer", canEdit: false}
]
}
When roles don't grow infinitely, embedding is efficient. It allows single-query data retrieval and atomic updates. However, you lose the ability to query roles separately from the User, complicating queries like finding shared roles between users.
MongoDB One-to-Many
If a User has many Posts with numerous attributes, embedding can be impractical due to document size limits. Instead, referencing is appropriate:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01",
posts: [234, 432]
}
Post Documents
{
id: 234,
title: "favorite pizza",
location: "Los Angeles"
}
{
id: 432,
title: "need a break?",
location: "Sacramento"
}
Referencing prevents unmanageable document size growth and enables independent data querying, like searching posts by keywords. The drawback is that additional queries are required to join related data like retrieving all user posts.
MongoDB One-to-Infinity
In scenarios like users following others, where potential relationships are vast, child referencing fits best:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01"
}
Following Documents
{
id: 1234,
follower: 234,
following: 112,
createdAt: "2017-12-01"
}
Here, the User document skips listing followers or followings directly, using a separate collection for relationships. This keeps the User documents compact and allows effective querying over these relationships.
Two Way Referencing
For a blend of efficiency and detail, two way referencing is valuable. Expanding on the follower example, consider:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01",
followers: [234]
}
Following Documents
{
id: 234,
follower: 234,
following: 112,
createdAt: "2017-12-01"
}
This setup enables quick counts of followers through the User document without querying the Following collection. However, due to added complexity, atomic updates become infeasible—updates require changes in multiple documents.
Denormalization
Denormalization involves reducing joins by repeating data, as with including follower information directly in User documents:
User Document
{
id: 112,
name: "Sam",
email: "sam@gmail.com",
createdAt: "2017-12-01",
updatedAt: "2017-12-01",
followers: [{id: 234, name: "Fred"}]
}
Following Documents
{
id: 234,
follower: 234,
following: 112,
createdAt: "2017-12-01"
}
This avoids extra queries but requires updating multiple documents when a user's data changes.
MongoDB Schema Design for Real-World Examples
Use cardinals and query patterns to guide real-world schema design. For frequently read data with few updates, denormalization or two-way referencing is optimal. Consider:
"How often will I update this data?"
"How large will documents grow?"
Combine strategies based on these crucial questions.
Conclusion
Mongodb schema design isn't one-size-fits-all but varies per application's requirements. Recognizing cardinality's role and the balance between embedding and referencing can harness MongoDB's scalability.
FAQ
What is the main benefit of embedding documents in MongoDB?
Embedding documents allow for retrieving related information in a single query without requiring joins, improving performance for certain use cases.
How does cardinality affect schema design?
Cardinality influences your choice between embedding and referencing. High cardinality relationships often require referencing to manage size and complexity effectively.
When should I use denormalization in MongoDB?
Denormalization is best suited when you're facing frequent read operations and want to avoid expensive join queries, despite the increased maintenance overhead.
What is a document size limit in MongoDB?
As of now, MongoDB has a document size limit of 16MB. Understanding this helps in deciding when to stop embedding data and shift to referencing.

