Practical Design Workshop: An Online Learning Platform

Design the schema from requirements

Build a model for a learning platform with:

  • users,
  • courses,
  • lessons,
  • enrollments,
  • progress,
  • comments,
  • and course reviews.

Requirements:

  1. A course page displays course title, summary, instructor, and a bounded set of lesson summaries.
  2. A course may contain hundreds of lessons and lesson content may be large.
  3. Each user can enroll in many courses; each course can have many users.
  4. Enrollment stores status, progress, and enrolled time.
  5. Users can update progress frequently.
  6. Comments and reviews can grow without bound.
  7. The course page should show the latest three reviews without scanning the entire review history.

Suggested collection responsibilities

users

  • Profile and account-level data.
  • Embed small profile preferences.
  • Keep authentication/security information protected and appropriately separated.

courses

  • Course metadata and instructor reference.
  • Embed a small, bounded set of featured lesson summaries only if it helps the course page.
  • Store large lesson bodies separately.

lessons

  • courseId, lesson order, title, content, duration, publication status.
  • Index by { courseId: 1, order: 1 }.

enrollments

  • userId, courseId, status, enrolledAt, progressPercent.
  • Unique compound index on { userId: 1, courseId: 1 }.
  • Add indexes for common user-history and course-roster queries.

lessonProgress

  • Use if progress is tracked independently for every lesson and can grow substantially.
  • A unique compound index on { userId: 1, lessonId: 1 } prevents duplicate progress records.

comments and reviews

  • Separate collections for unbounded user-generated content.
  • Index by the parent identifier and creation time.
  • Store only a bounded latest-review subset on the course if the page needs it.

Example indexes

db.lessons.createIndex({ courseId: 1, order: 1 });

db.enrollments.createIndex(
  { userId: 1, courseId: 1 },
  { unique: true }
);

db.enrollments.createIndex({ courseId: 1, status: 1, enrolledAt: -1 });

db.lessonProgress.createIndex(
  { userId: 1, lessonId: 1 },
  { unique: true }
);

db.reviews.createIndex({ courseId: 1, createdAt: -1, _id: -1 });

db.comments.createIndex({ courseId: 1, createdAt: -1, _id: -1 });

Design review questions

  • Is every embedded array bounded?
  • Can a course page be rendered without loading every lesson body?
  • Can a user have only one enrollment per course?
  • Can progress be updated without rewriting the enrollment document on every lesson event?
  • How are deleted users represented in historical reviews?
  • Is the latest-review subset a cache or a source of truth?
  • What happens when the course title changes after a review is submitted?
  • Which reads need strongly consistent values and which can tolerate a short delay?

The model is a starting point, not a universal prescription. Confirm it with real endpoint traces, realistic data, indexes, and load tests.

Specifications & Requirements
  • Lesson index:{ courseId: 1, order: 1 } supports ordered lessons for one course.
  • Enrollment uniqueness:A unique { userId: 1, courseId: 1 } index prevents duplicate enrollment pairs.
  • Review pagination:A compound parent/time index supports recent review retrieval.
Note

Extend this design with an explicit lifecycle policy for courses, lessons, enrollments, comments, and reviews. Include what happens when a user or course is deleted or archived.

Create core indexes for the learning platform
db.lessons.createIndex({ courseId: 1, order: 1 });

db.enrollments.createIndex(
  { userId: 1, courseId: 1 },
  { unique: true }
);

db.lessonProgress.createIndex(
  { userId: 1, lessonId: 1 },
  { unique: true }
);

db.reviews.createIndex({
  courseId: 1,
  createdAt: -1,
  _id: -1
});
Key Takeaways
  • Separate large lesson content and unbounded user-generated content from course metadata.
  • Model enrollment as a relationship with its own attributes.
  • Use unique indexes to enforce uniqueness requirements and compound indexes for common query patterns.
Knowledge Check

Which collection is the best place for an unbounded set of course comments that needs independent pagination?