MongoDB Mastery
MongoDB Mastery lessons / Module 1: MongoDB Fundamentals

Documents, collections and namespaces

Level 1: Beginner15 min

The rules every document follows: _id, field names, size limits, nesting, and how collections and databases are created.

This lesson is interactive. Run every example against an in-browser MongoDB, see explain() plans drawn as trees, and take the quiz.
Open the interactive lesson
You will learn to
  • Know the constraints on documents (16 MB, _id, field names)
  • Understand implicit creation of databases and collections
  • Use dot notation to reach nested fields
  • Explain what a namespace is

conceptThe concept

  • _id: required, unique per collection, immutable, can be any type except an array. Default is an ObjectId.
  • Size: a document can be at most 16 MB of BSON. Nesting depth is limited to 100 levels.
  • Field names: case-sensitive strings. Avoid names that start with $ or contain .; they are legal since 5.0 but awkward to query.
  • Field order is preserved; _id is always first.
  • Namespace: database.collection, for example shop.orders. Indexes, the oplog and the profiler all refer to namespaces.

Databases and collections are created lazily: the first insert into db.newThing creates both. Use db.createCollection() when you need options such as a validator, capped size, time series or clustered index.

whyWhy it matters

The 16 MB limit and the shape of your documents drive schema design. Arrays that grow without bound (every click a user ever made) eventually hit the limit and make every read and write of that document expensive. Knowing the rules early prevents designs you would have to migrate later.

Use caseReal-world scenario

A customer document embeds the current address (bounded, read with the customer), but the list of orders lives in its own collection referencing customerId, because a loyal customer could place thousands of orders.

Try itExamples

Run and edit these in the interactive lesson.

Dot notation into embedded documents
db.customers.find({ "address.city": "Pune" }, { name: 1, address: 1 }).limit(3)
db.customers.countDocuments({ "address.country": "India" })
Lazy creation
use lab
db.notes.insertOne({ text: "first note", tags: ["intro"] })
show collections
db.notes.find()
use shop
Explicit creation with options
use lab
db.audit.drop()
db.createCollection("audit", { capped: true, size: 1048576, max: 3 })
for (let i = 1; i <= 5; i++) db.audit.insertOne({ seq: i })
db.audit.find({}, { _id: 0 })
use shop
A capped collection keeps only the newest documents (here at most 3), in insertion order.

internalsUnder the hood

Each collection is a WiredTiger table keyed by an internal RecordId; the _id index maps your _id values to RecordIds. Since 5.3 you can create clustered collections where documents are stored in _id order and the separate _id index disappears, which helps time-ordered data.

Avoid / preferDo this, not that

Avoid
db.metrics.insertOne({ "cpu.load": 0.7, "$price": 10 })
Prefer
db.metrics.insertOne({ cpu: { load: 0.7 }, price: 10 })

Since 5.0 field names may contain dots and dollar signs, but the query language reads dots as paths and dollars as operators. Reaching those fields needs $getField and $setField; ordinary names avoid the trouble.

Avoid
db.users.updateOne({ _id: 1 },
  { $push: { logins: new Date() } })   // forever
Prefer
db.users.updateOne({ _id: 1 },
  { $push: { logins: { $each: [new Date()], $slice: -50 } } })

An array that grows forever eventually hits the 16 MB document limit, and every update rewrites an ever larger document. Cap it with $slice, or move history into its own collection.

PitfallsCommon mistakes

  • Storing unbounded arrays (comments, events, logs) inside one document.
  • Using values such as user input as field names ({ "user@example.com": ... }). Field names should be static; put variable data in values.
  • Typos in collection names silently create new collections. db.order.insertOne() writes to order, not orders.

LimitsWhen not to use it

Do not use one document as a container for a whole tenant or a whole day of events, and do not create one collection per customer or per day by the thousands. Every collection and index is a separate WiredTiger file; tens of thousands of them slow startup, checkpoints and memory use. Use a field such as tenantId instead.

SecuritySecurity notes

Values of _id and unique-index fields are echoed in duplicate-key errors and in slow-query logs. Avoid using emails, phone numbers or national ID numbers as _id; use an opaque id and keep personal data in ordinary fields. MongoDB Enterprise can also redact client data from logs with redactClientLogData.

ChallengeTry it yourself

Find the three largest order documents by BSON size, showing orderNo, the number of line items and the size in bytes.

Show one solution
One solution
db.orders.aggregate([
  { $project: { orderNo: 1, items: { $size: "$items" }, bytes: { $bsonSize: "$$ROOT" } } },
  { $sort: { bytes: -1 } },
  { $limit: 3 }
])

InterviewQuestions you should be able to answer

What happens if two documents in a collection have different fields?

Nothing breaks; collections do not enforce a structure unless you add a validator. Queries simply do not match documents missing a field (unless you query for missing values). In practice you keep shapes consistent per type and use a $jsonSchema validator for critical fields.

How do you handle data that might exceed 16 MB?

Do not let a single document grow without bound: move the growing part into its own collection (one document per item or per bucket of items), use the bucket pattern, or store large binary content with GridFS or object storage and keep a reference.

QuizCheck your understanding

4 questions with instant feedback in the interactive lesson; a wrong answer goes into your review deck.