Practical Lab: Build Your First Learning Database

This lab combines the concepts from the chapter into a small learning-platform dataset. Run the commands in mongosh against a development database.

Step 1: Select the practice database

use mongodb_course_lab

Step 2: Insert sample courses

db.courses.insertMany([
  {
    slug: "mongodb-basics",
    title: "MongoDB Basics",
    category: "database",
    level: "beginner",
    durationMinutes: 120,
    published: true,
    tags: ["mongodb", "nosql", "backend"],
    instructor: {
      name: "Kavitha",
      country: "India"
    },
    createdAt: ISODate("2026-10-01T09:00:00Z")
  },
  {
    slug: "mongodb-querying",
    title: "MongoDB Querying in Depth",
    category: "database",
    level: "intermediate",
    durationMinutes: 240,
    published: true,
    tags: ["mongodb", "queries", "backend"],
    instructor: {
      name: "Arun",
      country: "India"
    },
    createdAt: ISODate("2026-10-05T09:00:00Z")
  },
  {
    slug: "react-foundations",
    title: "React Foundations",
    category: "frontend",
    level: "beginner",
    durationMinutes: 180,
    published: false,
    tags: ["react", "javascript", "frontend"],
    instructor: {
      name: "Meera",
      country: "India"
    },
    createdAt: ISODate("2026-10-08T09:00:00Z")
  },
  {
    slug: "mongodb-data-modeling",
    title: "MongoDB Data Modeling",
    category: "database",
    level: "advanced",
    durationMinutes: 360,
    published: true,
    tags: ["mongodb", "schema-design", "architecture"],
    instructor: {
      name: "Kavitha",
      country: "India"
    },
    createdAt: ISODate("2026-10-12T09:00:00Z")
  }
]);

Step 3: Inspect the inserted records

db.courses.find();

Observe the _id values generated by MongoDB. Inspect the arrays, nested instructor documents, dates, and scalar fields.

Step 4: Filter by category

db.courses.find({ category: "database" });

This query returns the database courses. It does not require every document in the collection to belong to that category.

Step 5: Query a nested field

db.courses.find({ "instructor.name": "Kavitha" });

The query uses dot notation to select courses taught by Kavitha.

Step 6: Filter by multiple conditions

db.courses.find({
  category: "database",
  published: true
});

Multiple fields in a standard query filter are combined using logical AND. A document must satisfy both conditions to match.

Step 7: Return selected fields

db.courses.find(
  { published: true },
  { _id: 0, title: 1, level: 1, durationMinutes: 1 }
);

The first argument specifies which documents to match. The second argument specifies which fields to return. This projection excludes _id and includes the three requested fields.

Step 8: Count published courses

db.courses.countDocuments({ published: true });

With the supplied data, this should return 3.

Step 9: Inspect a date range

db.courses.find({
  createdAt: {
    $gte: ISODate("2026-10-05T00:00:00Z"),
    $lt: ISODate("2026-10-13T00:00:00Z")
  }
});

This query uses an inclusive lower bound and an exclusive upper bound. It returns documents created on or after October 5 and before October 13, 2026, according to the stored UTC dates.

Step 10: Clean up when finished

If this is a disposable practice database and you want to remove the lab collection, run:

db.courses.drop();

This deletes the collection and its documents. Do not run destructive commands against a production collection.

Lab challenges

  1. Find every course whose level is beginner.
  2. Find published courses taught by Arun.
  3. Return only slug and title for frontend courses.
  4. Count all courses in the database category.
  5. Find courses whose tags contain backend.
  6. Find courses created after October 5, 2026.
  7. Explain why instructor.name is a nested field path rather than a separate top-level field.
  8. Describe one reason you might keep enrollments in a separate collection rather than embedding an unbounded enrollment history inside each course.
Lab answer examples
// 1. Beginner courses
db.courses.find({ level: "beginner" });

// 2. Published courses taught by Arun
db.courses.find({
  published: true,
  "instructor.name": "Arun"
});

// 3. Slug and title for frontend courses
db.courses.find(
  { category: "frontend" },
  { _id: 0, slug: 1, title: 1 }
);

// 4. Count database courses
db.courses.countDocuments({ category: "database" });

// 5. Courses whose tags contain backend
db.courses.find({ tags: "backend" });

// 6. Courses created after October 5, 2026
db.courses.find({
  createdAt: { $gt: ISODate("2026-10-05T00:00:00Z") }
});
💡 These queries reinforce exact-match filters, nested field paths, projections, counting, array-element matching, and date comparisons. A filter such as { tags: "backend" } matches documents whose tags array contains that value. The date example uses a BSON Date boundary rather than comparing strings.
Key Takeaways
  • A single collection can contain documents with nested fields and arrays.
  • Multiple ordinary filter fields are combined using AND.
  • Projection controls which fields are returned.
  • Array fields can be queried by matching an element.
  • BSON Date values support chronological range filtering.
  • Destructive collection operations should be restricted to appropriate development environments.
Knowledge Check

Given the lab dataset, how many courses match `{ category: "database", published: true }`?