MongoDB is a popular NoSQL database that stores data in flexible, JSON-like documents. This guide covers everything you need to know to get started with MongoDB.
What is MongoDB? #
MongoDB is a document-oriented NoSQL database that stores data in flexible, JSON-like documents called BSON (Binary JSON). Unlike relational databases, MongoDB doesn’t require a predefined schema.
Why Use MongoDB? #
- Flexible schema - Easy to change data structure
- Scalable - Horizontal scaling with sharding
- High performance - Fast reads and writes
- Rich query language - Powerful querying capabilities
- Document-based - Natural mapping to objects in code
Installation #
# macOS (using Homebrew)
brew install mongodb-community
# Start MongoDB
brew services start mongodb-community
# Ubuntu
sudo apt-get install mongodb
# Start MongoDB
sudo systemctl start mongodbMongoDB Shell #
# Connect to MongoDB
mongosh
# or for older versions
mongoBasic Concepts #
- Database - Container for collections
- Collection - Group of documents (like a table)
- Document - A record (like a row), stored as BSON
- Field - A key-value pair in a document (like a column)
Database Operations #
// Show all databases
show dbs
// Create/switch to database
use myapp
// Show current database
db
// Drop database
db.dropDatabase()Collection Operations #
// Create collection
db.createCollection('users')
// Show collections
show collections
// Drop collection
db.users.drop()Inserting Documents #
Insert One #
db.users.insertOne({
name: 'Alice',
email: 'alice@example.com',
age: 25,
city: 'New York'
})
// Returns: { acknowledged: true, insertedId: ObjectId('...') }
Insert Many #
db.users.insertMany([
{
name: 'Bob',
email: 'bob@example.com',
age: 30,
city: 'San Francisco'
},
{
name: 'Charlie',
email: 'charlie@example.com',
age: 28,
city: 'Seattle'
}
])Querying Documents #
Find All #
db.users.find()
// Pretty print
db.users.find().pretty()Find with Criteria #
// Find one
db.users.findOne({ name: 'Alice' })
// Find by exact match
db.users.find({ city: 'New York' })
// Find by age
db.users.find({ age: 25 })
// Multiple conditions (AND)
db.users.find({ city: 'New York', age: 25 })
// OR conditions
db.users.find({
$or: [
{ city: 'New York' },
{ city: 'San Francisco' }
]
})Comparison Operators #
// Greater than
db.users.find({ age: { $gt: 25 } })
// Greater than or equal
db.users.find({ age: { $gte: 25 } })
// Less than
db.users.find({ age: { $lt: 30 } })
// Less than or equal
db.users.find({ age: { $lte: 30 } })
// Not equal
db.users.find({ city: { $ne: 'New York' } })
// In array
db.users.find({ city: { $in: ['New York', 'Seattle'] } })
// Not in array
db.users.find({ city: { $nin: ['New York', 'Seattle'] } })
// Range
db.users.find({ age: { $gte: 25, $lte: 30 } })Projection (Select Fields) #
// Include specific fields (exclude _id)
db.users.find({}, { name: 1, email: 1, _id: 0 })
// Exclude specific fields
db.users.find({}, { password: 0 })Sorting #
// Ascending
db.users.find().sort({ age: 1 })
// Descending
db.users.find().sort({ age: -1 })
// Multiple fields
db.users.find().sort({ city: 1, age: -1 })Limiting and Skipping #
// Limit results
db.users.find().limit(5)
// Skip results (pagination)
db.users.find().skip(10).limit(5)
// Combined: Page 2 with 5 items per page
db.users.find()
.sort({ age: 1 })
.skip(5)
.limit(5)Counting #
// Count all documents
db.users.countDocuments()
// Count with filter
db.users.countDocuments({ city: 'New York' })Updating Documents #
Update One #
// Update single field
db.users.updateOne(
{ name: 'Alice' },
{ $set: { age: 26 } }
)
// Update multiple fields
db.users.updateOne(
{ name: 'Alice' },
{ $set: { age: 26, city: 'Boston' } }
)Update Many #
// Update all matching documents
db.users.updateMany(
{ city: 'New York' },
{ $set: { country: 'USA' } }
)Update Operators #
// Increment
db.users.updateOne(
{ name: 'Alice' },
{ $inc: { age: 1 } }
)
// Multiply
db.users.updateOne(
{ name: 'Alice' },
{ $mul: { score: 1.1 } }
)
// Rename field
db.users.updateOne(
{ name: 'Alice' },
{ $rename: { 'name': 'fullName' } }
)
// Unset (remove field)
db.users.updateOne(
{ name: 'Alice' },
{ $unset: { age: '' } }
)
// Current date
db.users.updateOne(
{ name: 'Alice' },
{ $currentDate: { lastModified: true } }
)Upsert #
Insert if not exists, update if exists:
db.users.updateOne(
{ email: 'new@example.com' },
{ $set: { name: 'New User', age: 25 } },
{ upsert: true }
)Deleting Documents #
// Delete one
db.users.deleteOne({ name: 'Alice' })
// Delete many
db.users.deleteMany({ city: 'New York' })
// Delete all
db.users.deleteMany({})Array Operations #
Documents with Arrays #
db.posts.insertOne({
title: 'My Post',
tags: ['mongodb', 'database', 'nosql'],
comments: [
{ user: 'Alice', text: 'Great post!' },
{ user: 'Bob', text: 'Thanks for sharing' }
]
})Query Arrays #
// Contains value
db.posts.find({ tags: 'mongodb' })
// All values
db.posts.find({ tags: { $all: ['mongodb', 'database'] } })
// Array size
db.posts.find({ tags: { $size: 3 } })
// Element match
db.posts.find({
comments: {
$elemMatch: { user: 'Alice', text: /Great/ }
}
})Update Arrays #
// Add to array
db.posts.updateOne(
{ title: 'My Post' },
{ $push: { tags: 'tutorial' } }
)
// Add multiple
db.posts.updateOne(
{ title: 'My Post' },
{ $push: { tags: { $each: ['beginner', 'guide'] } } }
)
// Add if not exists
db.posts.updateOne(
{ title: 'My Post' },
{ $addToSet: { tags: 'mongodb' } }
)
// Remove from array
db.posts.updateOne(
{ title: 'My Post' },
{ $pull: { tags: 'nosql' } }
)
// Remove first or last
db.posts.updateOne(
{ title: 'My Post' },
{ $pop: { tags: 1 } } // 1 for last, -1 for first
)Embedded Documents #
db.users.insertOne({
name: 'Alice',
address: {
street: '123 Main St',
city: 'New York',
zip: '10001'
},
preferences: {
theme: 'dark',
notifications: true
}
})
// Query embedded documents
db.users.find({ 'address.city': 'New York' })
// Update embedded field
db.users.updateOne(
{ name: 'Alice' },
{ $set: { 'address.zip': '10002' } }
)Indexes #
Improve query performance:
// Create index
db.users.createIndex({ email: 1 })
// Compound index
db.users.createIndex({ city: 1, age: -1 })
// Unique index
db.users.createIndex({ email: 1 }, { unique: true })
// Text index
db.posts.createIndex({ title: 'text', content: 'text' })
// Show indexes
db.users.getIndexes()
// Drop index
db.users.dropIndex('email_1')Aggregation Pipeline #
Powerful data processing:
// Group by and count
db.users.aggregate([
{
$group: {
_id: '$city',
count: { $sum: 1 }
}
}
])
// Match and group
db.users.aggregate([
{ $match: { age: { $gte: 25 } } },
{
$group: {
_id: '$city',
avgAge: { $avg: '$age' },
count: { $sum: 1 }
}
},
{ $sort: { avgAge: -1 } }
])
// Project (select fields)
db.users.aggregate([
{
$project: {
name: 1,
email: 1,
ageInMonths: { $multiply: ['$age', 12] }
}
}
])
// Unwind arrays
db.posts.aggregate([
{ $unwind: '$tags' },
{ $group: { _id: '$tags', count: { $sum: 1 } } },
{ $sort: { count: -1 } }
])
// Lookup (join)
db.orders.aggregate([
{
$lookup: {
from: 'users',
localField: 'userId',
foreignField: '_id',
as: 'user'
}
}
])Using MongoDB with Node.js #
npm install mongodbconst { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
async function main() {
await client.connect();
console.log('Connected to MongoDB');
const db = client.db('myapp');
const users = db.collection('users');
// Insert
await users.insertOne({
name: 'Alice',
email: 'alice@example.com'
});
// Find
const user = await users.findOne({ name: 'Alice' });
console.log(user);
// Find many
const allUsers = await users.find().toArray();
console.log(allUsers);
// Update
await users.updateOne(
{ name: 'Alice' },
{ $set: { age: 26 } }
);
// Delete
await users.deleteOne({ name: 'Alice' });
await client.close();
}
main().catch(console.error);Using Mongoose (ODM) #
npm install mongooseconst mongoose = require('mongoose');
// Connect
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// Define schema
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
age: Number,
createdAt: { type: Date, default: Date.now }
});
// Create model
const User = mongoose.model('User', userSchema);
// Create document
async function createUser() {
const user = new User({
name: 'Alice',
email: 'alice@example.com',
age: 25
});
await user.save();
console.log('User created:', user);
}
// Find documents
async function findUsers() {
const users = await User.find({ age: { $gte: 25 } });
console.log(users);
}
// Update document
async function updateUser() {
const user = await User.findOneAndUpdate(
{ name: 'Alice' },
{ $set: { age: 26 } },
{ new: true }
);
console.log('Updated user:', user);
}
// Delete document
async function deleteUser() {
await User.deleteOne({ name: 'Alice' });
console.log('User deleted');
}Data Modeling #
One-to-One (Embedded) #
{
_id: ObjectId('...'),
name: 'Alice',
address: {
street: '123 Main St',
city: 'New York'
}
}One-to-Many (Embedded) #
{
_id: ObjectId('...'),
name: 'Alice',
orders: [
{ orderId: 1, total: 100 },
{ orderId: 2, total: 200 }
]
}One-to-Many (Referenced) #
// User document
{
_id: ObjectId('user1'),
name: 'Alice'
}
// Order documents
{
_id: ObjectId('order1'),
userId: ObjectId('user1'),
total: 100
}Many-to-Many #
// Student
{
_id: ObjectId('student1'),
name: 'Alice',
courseIds: [ObjectId('course1'), ObjectId('course2')]
}
// Course
{
_id: ObjectId('course1'),
title: 'MongoDB Basics',
studentIds: [ObjectId('student1'), ObjectId('student2')]
}Best Practices #
- Use appropriate data model - Embed vs reference
- Index frequently queried fields
- Limit document size - Max 16MB per document
- Use projection - Don’t fetch unnecessary fields
- Use aggregation pipeline for complex queries
- Avoid large arrays - Can impact performance
- Use connection pooling
- Handle errors properly
- Use schema validation with Mongoose
- Back up your data regularly
MongoDB vs SQL #
| Feature | MongoDB | SQL |
|---|---|---|
| Data Model | Document | Relational |
| Schema | Flexible | Fixed |
| Scaling | Horizontal | Vertical |
| Joins | Limited | Full support |
| Transactions | Multi-document | ACID |
| Query Language | JavaScript-like | SQL |
Common Use Cases #
Best for:
- Flexible/evolving schemas
- High write loads
- Hierarchical data
- Real-time analytics
- Content management
Not ideal for:
- Complex transactions
- Complex joins
- Financial data requiring ACID
- Reporting with complex aggregations
MongoDB provides flexibility and scalability for modern applications. Understanding these fundamentals will help you leverage its power effectively.