MongoDB Basics - Complete Guide

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 mongodb

MongoDB Shell #

# Connect to MongoDB
mongosh

# or for older versions
mongo

Basic 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 mongodb
const { 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 mongoose
const 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 #

  1. Use appropriate data model - Embed vs reference
  2. Index frequently queried fields
  3. Limit document size - Max 16MB per document
  4. Use projection - Don’t fetch unnecessary fields
  5. Use aggregation pipeline for complex queries
  6. Avoid large arrays - Can impact performance
  7. Use connection pooling
  8. Handle errors properly
  9. Use schema validation with Mongoose
  10. Back up your data regularly

MongoDB vs SQL #

FeatureMongoDBSQL
Data ModelDocumentRelational
SchemaFlexibleFixed
ScalingHorizontalVertical
JoinsLimitedFull support
TransactionsMulti-documentACID
Query LanguageJavaScript-likeSQL

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.