The Document Data Model & Schema Design

MongoDB Fundamentals — The Document Data Model & Schema Design
MongoDB Fundamentals
Chapter 5 · The Document Data Model & Schema Design

🧩 The Document Data Model & Schema Design

Chapters 3–4 covered CRUD mechanically. This chapter covers the decision that matters most in MongoDB: how to actually shape your documents — contrasted throughout with the normalization-first approach the MySQL course's mysql_advanced_01 chapter builds around.

Embedding vs. Referencing: The Core Decision

Every relationship between two pieces of data can be represented one of two ways: embedding the related data directly inside the parent document (as Chapter 1's blog post + comments example did), or referencing it — storing just an _id pointing to a separate document in another collection, conceptually similar to a MySQL foreign key.

Embedding vs. Referencing

Embedding

Related data lives directly inside the parent document. One read gets everything — no second query needed — but the data can only grow so far before that becomes a liability.

Referencing

The parent stores just an id; the related data lives in its own collection, looked up separately. More like a relational foreign key, at the cost of a second query when you need both.

When to Embed

Embed when the related data is always read together with its parent, doesn't grow without bound, and conceptually belongs to one single "thing" — an address embedded in a user, or a handful of recent comments embedded in a post, exactly as Chapter 1 modeled it.

When to Reference

Reference when the related data is large or effectively unbounded, shared and reused across many different parent documents, or frequently queried independently of whatever "owns" it.

Referencing a Shared Category

// products collection — references a category, doesn't embed it { name: "Laptop", categoryId: ObjectId("64f9...") } // categories collection — one shared document per category { _id: ObjectId("64f9..."), name: "Electronics", taxRate: 0.2 }

If "Electronics" instead got embedded directly into every product document, renaming the category or changing its tax rate would mean updating potentially thousands of product documents at once — referencing means updating exactly one document.

Denormalization: A Deliberate Choice, Not Sloppiness

The MySQL course's normalization chapter treats duplicated data as something to design away. MongoDB documents often duplicate data on purpose, trading some update complexity for read performance — for example, embedding a post's author name directly on the post, not just an authorId reference, so displaying a post never needs a second lookup just to show who wrote it. The trade-off is real: if that author later changes their display name, every post that embedded the old name needs updating (or the staleness has to be accepted temporarily) — precisely the "update anomaly" relational normalization exists to prevent. MongoDB doesn't eliminate that trade-off; it just makes it a deliberate, chapter-by-chapter design choice rather than something the database forces on you either way.

One-to-Many Relationships

Relationship ShapeExampleRecommended Pattern
One-to-fewA user with a few addressesEmbed as an array
One-to-many (bounded)A post with a manageable number of commentsEmbed, with an eye on growth
One-to-squillionsA device generating millions of log entriesAlways reference — never embed

Many-to-Many Relationships

Take students and courses — a student takes many courses, and a course has many students. The most direct pattern: store an array of course _ids on the student document (or vice versa). For a genuinely many-to-many relationship with its own attributes (like an enrollment date or a grade), a separate join collection often works better — the exact document-model counterpart to a MySQL join table:

A Join Collection for Enrollments

// enrollments collection — one document per student-course pairing { studentId: ObjectId("..."), courseId: ObjectId("..."), enrolledAt: ISODate("2026-01-10") }

💻 Coding Challenges

Challenge 1: Embed or Reference?

For each, recommend embedding or referencing: (a) a user's shipping addresses (typically 1-3 per user), (b) a YouTube-style video's comments (potentially tens of thousands), (c) a "country" field shared by millions of user documents.

Goal: Practice applying the growth/sharing criteria this chapter introduced.

→ Solution

Challenge 2: Design a Many-to-Many Relationship

Design the document(s) for a many-to-many relationship between "authors" and "books" (an author can write several books; a book can have several co-authors), including a way to store each author's specific royalty percentage on a given book.

Goal: Practice the join-collection pattern for a many-to-many relationship that carries its own data.

→ Solution

Challenge 3: Identify a Denormalization Trade-off

A product document embeds its supplier's name directly (not just a supplierId). The supplier later rebrands and changes their name. Explain what happens to existing product documents, and how you might address it.

Goal: Practice reasoning through the real consequence of a denormalization decision made earlier.

→ Solution

⚠️ Gotcha: The 16MB Document Size Limit

Every MongoDB document has a hard maximum size of 16MB — not a soft guideline, an enforced limit. This is exactly why "one-to-squillions" relationships must be referenced rather than embedded: a viral post that keeps embedding new comments directly into its own document will eventually hit this ceiling, and further inserts/updates to that document will simply start failing. It's easy to overlook this while a post only has a handful of comments in testing — the failure only shows up once real growth happens, which is precisely why the growth pattern matters more than the current size when choosing between embedding and referencing.

🎯 What's Next

The next chapter covers Data Types & BSONObjectId, dates, arrays, and nested documents in more depth, plus schema validation with $jsonSchema for when you want to opt back into enforced structure.