Week 1: MongoDB Fundamentals — Documents, Collections & CRUD

This course assumes nothing about your prior database experience — just that you're comfortable reading JSON. This week builds the mental model everything else rests on: MongoDB stores flexible, JSON-like documents instead of rigid rows, and almost everything you'll do to them boils down to five operations you'll use in every single week that follows.

Module 1 of 10 Week 1 of 10 ~2–3 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Explain what a document, collection and database are in MongoDB
  • Perform all five core CRUD operations in mongosh
  • Explain what _id and ObjectId are, and why every document has one

1. Why MongoDB? Documents vs. Rows

A relational database (like the SQL you'd use elsewhere) stores data in rigid rows with a fixed set of columns, defined up front. MongoDB stores documents — JSON-like objects that can nest arrays and other objects directly inside them, and don't require every document in a collection to share the exact same shape.

a MongoDB document
{
  "_id": ObjectId("64f1a2b3c4d5e6f7a8b9c0d1"),
  "name": "Asha Rao",
  "email": "asha@example.com",
  "tags": ["premium", "newsletter"],
  "address": {
    "city": "Kolkata",
    "state": "West Bengal"
  }
}

That nested address object and the tags array would each need a separate, joined table in a relational database. Here, a single document holds the whole related shape in one place — which is exactly why document databases are such a natural fit for data that's naturally hierarchical: user profiles, product catalogs, content management, event logs.

"Schemaless" doesn't mean "no structure"

MongoDB doesn't enforce a schema at the database level by default, but every well-run application still has a consistent shape for its documents — it's just enforced in your application code (or with optional schema validation, covered in Week 3) instead of by the database engine itself.

2. Installing MongoDB & Connecting with mongosh

Install MongoDB Community Server locally, or skip local installation entirely and use a free MongoDB Atlas cluster in the cloud — either works for this course. mongosh is the official shell you'll use to run every command below.

terminal
# macOS (Homebrew)
brew tap mongodb/brew
brew install mongodb-community mongosh

# Ubuntu/Debian -- follow MongoDB's official apt instructions for your version
# Windows -- install the MSI from mongodb.com/try/download/community

# Start the server (if running locally)
mongod --dbpath /path/to/your/data/directory

# In a separate terminal, connect with the shell
mongosh
# Current Mongosh Log ID: ...
# Connecting to: mongodb://127.0.0.1:27017/
# Using MongoDB: 7.0.x

Once connected, mongosh is a full JavaScript environment — every command in this lesson is really a JavaScript method call on a database or collection object.

3. Databases, Collections & Documents

A MongoDB server hosts multiple databases. Each database holds collections (the rough equivalent of a table). Each collection holds documents (the rough equivalent of a row).

mongosh
// Switch to (or create) a database -- it's created on first write, not on this command
use school

// List every database that actually has data
show dbs

// List collections in the current database
show collections

// Explicitly create a collection (usually unnecessary -- insertOne does this automatically)
db.createCollection("students")
A database only shows up in show dbs once it has data

use school switches your session's context to that database name, but MongoDB doesn't actually create it on disk until you insert at least one document into a collection inside it. Running use alone is never enough to "create" a database.

4. CRUD Operations: The Five You'll Use Constantly

Every one of MongoDB's dozens of methods is a variation on five core operations. Learn these five well and you can already do real work.

mongosh
// CREATE -- insert one document
db.students.insertOne({ name: "Ben Diaz", grade: 9, gpa: 3.4 })

// CREATE -- insert many documents at once
db.students.insertMany([
  { name: "Chen Wei", grade: 10, gpa: 3.9 },
  { name: "Dev Patel", grade: 9, gpa: 2.8 }
])

// READ -- find every document
db.students.find()

// READ -- find with a filter, pretty-printed
db.students.find({ grade: 9 }).pretty()

// READ -- find exactly one document
db.students.findOne({ name: "Ben Diaz" })

// UPDATE -- modify one matching document
db.students.updateOne(
  { name: "Ben Diaz" },
  { $set: { gpa: 3.5 } }
)

// UPDATE -- modify every matching document
db.students.updateMany(
  { grade: 9 },
  { $set: { onProbation: false } }
)

// DELETE -- remove one matching document
db.students.deleteOne({ name: "Dev Patel" })

// DELETE -- remove every matching document
db.students.deleteMany({ grade: 9 })
Update operations need $set — don't skip it

Passing a plain object as the second argument to updateOne (without $set) replaces the entire document with just that object, silently dropping every other field. $set tells MongoDB to update only the named fields and leave the rest alone.

5. The _id Field & BSON Types

Every document gets an _id field automatically if you don't provide one — it's the primary key, and it's required and unique within a collection. By default MongoDB generates an ObjectId: a 12-byte value that encodes a timestamp, so IDs are roughly sortable by creation time even without a separate date field.

mongosh
db.students.insertOne({ name: "Eva Kim", grade: 11 })
// { acknowledged: true, insertedId: ObjectId("64f...") }

// You can supply your own _id instead, if it's meaningful in your domain
db.students.insertOne({ _id: "student-eva-kim", name: "Eva Kim", grade: 11 })

// Extract the creation time embedded in a default ObjectId
db.students.findOne({ name: "Eva Kim" })._id.getTimestamp()

Under the hood, MongoDB stores documents as BSON (Binary JSON) — a binary format that adds types plain JSON doesn't have, including ObjectId, native Date, and distinct integer/decimal number types. This is why a MongoDB document looks almost exactly like JSON but isn't literally JSON on disk.

6. Hands-on Exercise

Hands-on

Build and manage a small library collection

Practice all five CRUD operations against data you design yourself.

Requirements:

  1. Connect with mongosh and use library to switch to a new database.
  2. Use insertMany to add at least 5 books, each with title, author, year, available (boolean) and a genres array field.
  3. Write a find query returning only books where available is true.
  4. Use updateOne with $set to mark one book as checked out (available: false) — without overwriting its other fields.
  5. Use updateMany to add a new field, lastAudited: true, to every book at once.
  6. Use deleteOne to remove exactly one book, then confirm with find() that only that one is gone.
  7. Run findOne on any book and call .getTimestamp() on its _id to confirm it matches roughly when you inserted it.
Hint

If a book's other fields vanish after your updateOne, double check you used { $set: { available: false } } and not a bare { available: false } — the latter replaces the whole document.

7. Knowledge Check

Four quick questions. Expand each to check your answer.

Q1

What is the rough MongoDB equivalent of a row in a relational table?

A document. Unlike a row, a document can nest arrays and objects directly inside it, and documents within the same collection aren't required to share an identical set of fields.

Q2

Why does running just use school not make the database appear in show dbs?

use only switches your shell session's current database context — it doesn't write anything to disk. MongoDB only actually creates the database once you insert at least one document into a collection within it.

Q3

What goes wrong if you call updateOne({ name: "Ben" }, { gpa: 3.5 }) without $set?

Without $set, the second argument is treated as a full replacement document, not a partial update. The matched document gets entirely replaced with { gpa: 3.5 }, silently losing every other field it had — including its name.

Q4

What information is encoded inside a default MongoDB ObjectId?

A creation timestamp, among other components (a random value and a counter). That's why ObjectId values are roughly sortable by insertion time, and why calling .getTimestamp() on one returns a real date without the document needing its own separate date field.