Course Outline (Part 12)

In the previous module, we learned the mechanics of how to link data together using Embedding and Referencing. In this module, we will pull back the lens and look at the broader philosophy of Schema Design.

One of the greatest strengths of MongoDB is that it is “Schema-less” (or more accurately, it has a dynamic schema). However, just because you can throw any data you want into a collection doesn’t mean you should. Poor schema design will lead to sluggish performance, expensive queries, and spaghetti code on your backend.


Schema Design Principles

In a traditional SQL database, schema design is generally focused on the data itself. You build perfect, pristine tables that mathematically ensure no data is ever duplicated. This is called Third Normal Form (3NF).

In MongoDB, Schema design is driven by application access patterns.

Instead of asking, “How do I perfectly store this data?”, you must ask:

  1. How is my application going to read this data?
  2. How often will this data change?
  3. What is the most common query my users will run?

If your application always shows a User and their recent Orders on the same dashboard screen, your MongoDB schema should be designed to fetch that exact data in a single, lightning-fast query, even if it means duplicating some data.


Normalization (The SQL Way)

Normalization is the process of breaking your data apart into multiple, distinct collections and linking them together via References (ObjectIds).

Imagine a scenario where thousands of students are enrolled in a specific class.

Normalized Schema:

// The Class Collection
{
  "_id": ObjectId("CLASS_101"),
  "name": "Introduction to Computer Science",
  "instructor": "Dr. Smith"
}

// The Student Collection
{
  "_id": ObjectId("STUDENT_42"),
  "name": "Jane Doe",
  "enrolledClassId": ObjectId("CLASS_101") // Reference!
}

When to Normalize:

  • Use Normalization when the data changes frequently. (If Dr. Smith leaves and is replaced by Dr. Jones, you only have to update the instructor name in one single document in the Class collection).
  • Use it to prevent massive document growth. (A class might eventually have 100,000 students; embedding them all in the Class document would exceed the 16MB limit).

Denormalization (The NoSQL Way)

Denormalization is the process of intentionally duplicating or combining data into a single document to make read operations incredibly fast.

Let’s take the same scenario as above, but this time, the application frequently needs to display a list of all students and the name of the class they are taking. If we use the Normalized schema above, we would have to query the Student, and then do a secondary query to find the Class name.

Denormalized Schema:

// The Student Collection
{
  "_id": ObjectId("STUDENT_42"),
  "name": "Jane Doe",
  "enrolledClassId": ObjectId("CLASS_101"),
  "enrolledClassName": "Introduction to Computer Science" // Duplicated Data!
}

When to Denormalize:

  • Use Denormalization when your application reads the data 100x more often than it writes or updates it.
  • In this example, the name of the class (“Introduction to Computer Science”) rarely ever changes. By duplicating that string into every student’s document, the database can fetch the student’s full dashboard in a single query, completely eliminating the need for complex $lookup joins.

The Great Debate: Embedding vs Referencing

We covered the mechanics in Module 10, but let’s formalize the rules of when to Embed (Denormalize) and when to Reference (Normalize):

ScenarioStrategyWhy?
Contains (1-to-1)
e.g., User and User Settings
EmbedData is always accessed together and never grows.
One-to-Few
e.g., Product and Product Images
EmbedThe array is small and bounded. Faster reads.
One-to-Many
e.g., City and Citizens
ReferenceThe array is massive and unbounded. Avoid 16MB limit.
Many-to-Many
e.g., Books and Authors
ReferencePrevents updating thousands of duplicated fields if an author changes their name.

Best Practices for MongoDB Schema Design

If you follow these rules of thumb, your database will scale beautifully:

1. Favor Embedding by Default

Unless you have a compelling reason to separate the data (like rapid growth or frequent updates), embed it. The fewer collections you have to query, the faster your application will be.

2. Avoid Unbounded Arrays

Never embed an array that will grow forever. If you are building a Twitter clone, do not embed an array of “Tweets” inside the “User” document. A user might post 50,000 tweets, which will blow past the 16MB limit and cause massive performance degradation.

3. Duplication is Okay (Sometimes)

Do not be afraid to duplicate data if that data rarely changes (like a username, a category name, or a product title). Duplication speeds up reads immensely. Just be aware that if the data does change, you are responsible for updating it in multiple places.

4. Optimize for the Most Common Query

If 95% of your user traffic goes to the homepage, design your schema so that the homepage can be rendered with exactly one database query.


Summary

Schema design in MongoDB requires a mental shift from traditional SQL.

  • You must prioritize Application Access Patterns over pure data mathematics.
  • Use Normalization (Referencing) when data changes frequently or grows infinitely.
  • Use Denormalization (Embedding) when data is mostly static and you need incredibly fast read performance.

Now that we understand how to design our data structures, let’s step out of the shell and look at MongoDB Compass, the official graphical tool that makes managing these schemas a breeze!

Discussion

Loading comments...