Overview
MongoDB is a document-oriented NoSQL database that stores data as flexible BSON documents. It is popular for applications where the schema evolves quickly or where nested data would require multiple SQL joins. This tutorial covers the fundamentals with practical examples.
MongoDB vs Relational Databases
| Aspect | MongoDB | Relational |
|---|---|---|
| Data unit | Document (JSON-like) | Row |
| Schema | Flexible | Fixed |
| Relationships | Embedded documents or references | Foreign keys and joins |
| Query language | MongoDB Query Language | SQL |
| Scaling | Horizontal sharding built in | Often vertical first |
Installation Options
- Local: Install the Community Server from the MongoDB Community download page.
- Cloud: Create a free cluster on MongoDB Atlas.
- Container:
docker run -d -p 27017:27017 mongo:7
Connecting with mongosh
mongosh "mongodb://localhost:27017"
use myapp
db.users.insertOne({ name: "Alice", age: 30 })
CRUD Operations
Insert
db.users.insertOne({ name: "Bob", age: 25, tags: ["new"] })
db.users.insertMany([
{ name: "Carol", age: 28 },
{ name: "Dave", age: 35 }
])
Query
db.users.find({ age: { $gt: 28 } })
db.users.findOne({ name: "Alice" })
db.users.find({ tags: "new" })
Update
db.users.updateOne(
{ name: "Alice" },
{ $set: { age: 31 }, $push: { tags: "active" } }
)
db.users.updateMany(
{ age: { $lt: 30 } },
{ $inc: { age: 1 } }
)
Delete
db.users.deleteOne({ name: "Dave" })
db.users.deleteMany({ age: { $gt: 50 } })
Query Operators
| Operator | Meaning |
|---|---|
$eq / $ne | Equal / not equal |
$gt / $gte | Greater than / or equal |
$lt / $lte | Less than / or equal |
$in / $nin | In array / not in array |
$exists | Field present |
$regex | Regular expression match |
$and / $or | Logical combinations |
Sorting, Limiting, Projecting
db.users
.find({ age: { $gte: 18 } }, { name: 1, age: 1, _id: 0 })
.sort({ age: -1 })
.limit(10)
.skip(20)
Aggregation Pipeline
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$customerId",
total: { $sum: "$amount" },
orders: { $sum: 1 }
}},
{ $sort: { total: -1 } },
{ $limit: 5 }
])
| Stage | Purpose |
|---|---|
$match | Filter documents (like WHERE) |
$group | Aggregate (like GROUP BY) |
$sort | Order results |
$project | Select or compute fields |
$lookup | Join another collection |
$unwind | Expand an array field |
Indexes
db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ age: -1 })
db.users.createIndex({ name: "text", bio: "text" })
Use explain("executionStats") to confirm a query uses an index:
db.users.find({ email: "alice@example.com" }).explain("executionStats")
Look for IXSCAN in the winning plan. A COLLSCAN means the query is scanning the whole collection.
Schema Design Guidelines
- Embed when the data is always read together and bounded in size.
- Reference when the data is shared across documents or can grow without limit.
- Avoid unbounded arrays; they eventually hit the 16 MB document limit.
- Design indexes around your query patterns, not your data model.
