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

AspectMongoDBRelational
Data unitDocument (JSON-like)Row
SchemaFlexibleFixed
RelationshipsEmbedded documents or referencesForeign keys and joins
Query languageMongoDB Query LanguageSQL
ScalingHorizontal sharding built inOften 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

OperatorMeaning
$eq / $neEqual / not equal
$gt / $gteGreater than / or equal
$lt / $lteLess than / or equal
$in / $ninIn array / not in array
$existsField present
$regexRegular expression match
$and / $orLogical 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 }
])
StagePurpose
$matchFilter documents (like WHERE)
$groupAggregate (like GROUP BY)
$sortOrder results
$projectSelect or compute fields
$lookupJoin another collection
$unwindExpand 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.