After this lesson, you will be able to: Decide between embedding and referencing documents, design for query patterns, apply one-to-many + many-to-many patterns.
Schema design is where Mongo developers separate from beginners. Embed for read speed; reference for write flexibility. Design for HOW you query, not just what you store.
Embed (nested doc): data lives inside the parent. Fast read; updates touch one doc. Use when the embedded data is bounded + always loaded with the parent. Reference (separate collection + ObjectId): data lives in another doc. Update once, reflected everywhere. Use when the data grows unbounded, is shared, or is frequently queried alone.
User + addresses (a person has ~1-3 addresses).
{_id: ObjectId("..."),name: "Alex",addresses: [{ type: "home", street: "123 Main", city: "NYC" },{ type: "work", street: "456 5th", city: "NYC" }]}// Read: ONE query gets user + addresses// Update: db.users.updateOne({ _id }, { $push: { addresses: { ... } } })
User + posts (a user can have thousands of posts).
// users collection{ _id: ObjectId("u1"), name: "Alex" }// posts collection{ _id: ObjectId("p1"), userId: ObjectId("u1"), title: "...", body: "..." }{ _id: ObjectId("p2"), userId: ObjectId("u1"), title: "...", body: "..." }// Index posts.userId for fast lookupdb.posts.createIndex({ userId: 1, createdAt: -1 });// Read user's postsdb.posts.find({ userId: ObjectId("u1") }).sort({ createdAt: -1 });
Students + courses.
// Pattern 1: array of refs on one side (works if relationship is small){ _id: ObjectId("u1"), name: "Alex", courseIds: [ObjectId("c1"), ObjectId("c2")] }// Pattern 2: explicit junction collection (relational style; works at any scale)// enrollments{ _id, userId, courseId, enrolledAt, grade }// Pick by query pattern + scale:// - Mostly 'what courses is Alex in?' → array of refs is fine// - Need per-enrollment metadata (grade, dates)? → junction collection
Each Mongo document is capped at 16 MB. Sounds huge until you embed comments / messages / events. If a document grows unboundedly, you MUST reference, not embed. Common pattern: 'subset embedding', keep the last 10 comments embedded for fast first-page rendering; rest in separate collection with reference.
Embedding unbounded arrays (eventually hits 16 MB). Over-referencing (every query becomes a $lookup, using Mongo as bad SQL). Forgetting indexes on reference fields (slow joins via $lookup). Reaching for multi-document transactions on every write instead of designing the schema so single-document atomic updates suffice. Designing schema without knowing the queries.
Sign in and purchase access to unlock this lesson.