Introduction to MongoDB
MongoDB is the most widely used document database. Instead of tables and rows, it stores documents (JSON-like objects) grouped into collections. Its data model maps almost directly onto JavaScript objects, which is why it pairs so naturally with Node. This page covers MongoDB's vocabulary, the document model, BSON, and the design decisions — embedding vs referencing, indexing — that determine whether a Mongo schema performs well.
The vocabulary, translated from SQL
SQL term | MongoDB term |
|---|---|
Database | Database |
Table | Collection |
Row | Document |
Column | Field |
Primary key |
|
Join |
|
A document
{
"_id": { "$oid": "65f1a2b3c4d5e6f7a8b9c0d1" },
"name": "Ada Lovelace",
"email": "ada@example.com",
"roles": ["user", "editor"],
"address": { "city": "London", "zip": "EC1" },
"orders": [
{ "sku": "BK-1", "qty": 2, "price": 19.99 }
],
"createdAt": { "$date": "2026-01-12T09:30:00Z" }
}The defining decision: embed vs reference
// EMBED — related data inside the parent document (one read gets everything):
{ _id: 1, name: 'Ada', orders: [ { sku: 'BK-1', qty: 2 } ] }
// REFERENCE — store an id, look up separately (like a SQL foreign key):
{ _id: 1, name: 'Ada' }
{ _id: 9, userId: 1, sku: 'BK-1', qty: 2 } // separate 'orders' collectionEmbed when… | Reference when… |
|---|---|
Data is read together | Data is queried independently |
The relationship is "contains"/"part-of" | The relationship is "many-to-many" |
The sub-data is bounded in size | The sub-data grows unboundedly |
You want one fast read | The sub-data is shared/large |
Querying — by example documents
// Find — query is a document describing what to match:
db.users.find({ age: { $gte: 18 }, roles: 'editor' })
// Operators start with $:
{ age: { $gt: 18, $lt: 65 } } // range
{ status: { $in: ['active', 'trial'] } } // membership
{ 'address.city': 'London' } // nested field (dot notation)
{ tags: { $all: ['a', 'b'] } } // array contains allIndexes — non-negotiable for performance
// Without an index, a query SCANS every document (COLLSCAN):
db.users.find({ email: 'ada@example.com' }) // slow on a large collection
// Create an index so lookups are fast (and enforce uniqueness):
db.users.createIndex({ email: 1 }, { unique: true })
db.orders.createIndex({ userId: 1, createdAt: -1 }) // compoundThe aggregation pipeline (a glimpse)
// Transform/summarize data through a sequence of stages:
db.orders.aggregate([
{ $match: { status: 'paid' } }, // filter
{ $group: { _id: '$userId', total: { $sum: '$amount' } } }, // group + sum
{ $sort: { total: -1 } }, // sort
{ $limit: 10 }, // top 10 spenders
])Running MongoDB
MongoDB Atlas — the managed cloud service; easiest for production and a free tier for learning.
Docker —
docker run -d -p 27017:27017 mongofor a local instance.Local install — the Community Server for your OS.
Connect from Node with the official driver or the Mongoose ODM.