Section 5: Programming

🟒 MongoDB with Node.js

Complete tutorial on using MongoDB with Node.js - CRUD, async/await, Express integration

2 Drivers
CRUD Full Operations
Express REST API
Async Modern JS
βš™οΈ

Setup & Installation

Get started with MongoDB Node.js driver

Install MongoDB Driver

Terminal
# Initialize project
npm init -y

# Install MongoDB driver
npm install mongodb

# Optional: Install dotenv for environment variables
npm install dotenv
πŸ’‘ Package Versions

This tutorial uses MongoDB driver v6.x with modern async/await syntax. Requires Node.js 14+.

Project Structure

Project Layout
myproject/
β”œβ”€β”€ package.json
β”œβ”€β”€ .env
β”œβ”€β”€ config/
β”‚   └── db.js
β”œβ”€β”€ models/
β”‚   └── User.js
β”œβ”€β”€ routes/
β”‚   └── users.js
└── server.js
πŸ”Œ

Connecting to MongoDB

Establish database connection

Basic Connection

db.js
const { MongoClient } = require('mongodb');

// Connection string
// Local: 'mongodb://localhost:27017'
// Atlas: 'mongodb+srv://user:pass@cluster0.mongodb.net/'
const uri = 'mongodb://localhost:27017';

const client = new MongoClient(uri);

async function connectDB() {
  try {
    // Connect to MongoDB
    await client.connect();
    
    // Verify connection
    await client.db('admin').command({ ping: 1 });
    
    console.log('βœ… Connected to MongoDB!');
    
    // Get database
    const db = client.db('myapp');
    
    return db;
  } catch (error) {
    console.error('MongoDB connection error:', error);
    process.exit(1);
  }
}

async function closeDB() {
  await client.close();
  console.log('MongoDB connection closed');
}

module.exports = { connectDB, closeDB };

Environment Variables

.env
MONGODB_URI=mongodb://localhost:27017
DB_NAME=myapp
PORT=3000
Updated db.js
require('dotenv').config();
const { MongoClient } = require('mongodb');

const uri = process.env.MONGODB_URI;
const dbName = process.env.DB_NAME;

// Rest of the code...
πŸ’Ύ

CRUD Operations

Create, Read, Update, Delete with async/await

Insert Documents

Insert Operations
const { connectDB } = require('./config/db');

// Insert One
async function insertOne() {
  const db = await connectDB();
  const collection = db.collection('users');

  const user = {
    name: 'Alice Johnson',
    email: 'alice@example.com',
    age: 28,
    active: true,
    createdAt: new Date()
  };

  const result = await collection.insertOne(user);
  console.log(`Inserted ID: ${result.insertedId}`);
}

// Insert Many
async function insertMany() {
  const db = await connectDB();
  const collection = db.collection('users');

  const users = [
    { name: 'Bob Smith', email: 'bob@example.com', age: 35, active: true },
    { name: 'Carol White', email: 'carol@example.com', age: 42, active: false },
    { name: 'David Brown', email: 'david@example.com', age: 29, active: true }
  ];

  const result = await collection.insertMany(users);
  console.log(`Inserted ${result.insertedCount} documents`);
}

Find Documents

Find Operations
// Find One
async function findOne() {
  const db = await connectDB();
  const collection = db.collection('users');

  const user = await collection.findOne({ 
    email: 'alice@example.com' 
  });

  console.log('Found user:', user);
}

// Find Many
async function findMany() {
  const db = await connectDB();
  const collection = db.collection('users');

  // Find active users, sort by name, limit 10
  const users = await collection
    .find({ active: true })
    .sort({ name: 1 })
    .limit(10)
    .toArray();

  console.log(`Found ${users.length} users`);
  users.forEach(user => {
    console.log(`  - ${user.name} (${user.email})`);
  });
}

// Complex Query
async function complexQuery() {
  const db = await connectDB();
  const collection = db.collection('users');

  // Age between 25 and 40, and active
  const users = await collection.find({
    age: { $gte: 25, $lte: 40 },
    active: true
  }).toArray();

  console.log('Users between 25-40:', users);
}
πŸ’‘ Query Operators
  • $eq - Equal to
  • $gt, $gte - Greater than (or equal)
  • $lt, $lte - Less than (or equal)
  • $in - Matches any value in array
  • $and, $or - Logical operators
  • $regex - Regular expression match

Update Documents

Update Operations
// Update One
async function updateOne() {
  const db = await connectDB();
  const collection = db.collection('users');

  const result = await collection.updateOne(
    { email: 'alice@example.com' },
    { 
      $set: { 
        age: 29,
        updatedAt: new Date()
      }
    }
  );

  console.log(`Matched: ${result.matchedCount}`);
  console.log(`Modified: ${result.modifiedCount}`);
}

// Update Many
async function updateMany() {
  const db = await connectDB();
  const collection = db.collection('users');

  // Activate all inactive users
  const result = await collection.updateMany(
    { active: false },
    { $set: { active: true } }
  );

  console.log(`Updated ${result.modifiedCount} documents`);
}

// Increment Value
async function incrementAge() {
  const db = await connectDB();
  const collection = db.collection('users');

  await collection.updateOne(
    { email: 'alice@example.com' },
    { $inc: { age: 1 } } // Increment by 1
  );
}

Delete Documents

Delete Operations
// Delete One
async function deleteOne() {
  const db = await connectDB();
  const collection = db.collection('users');

  const result = await collection.deleteOne({ 
    email: 'alice@example.com' 
  });

  console.log(`Deleted ${result.deletedCount} document`);
}

// Delete Many
async function deleteMany() {
  const db = await connectDB();
  const collection = db.collection('users');

  // Delete users older than 50
  const result = await collection.deleteMany({ 
    age: { $gt: 50 } 
  });

  console.log(`Deleted ${result.deletedCount} documents`);
}
πŸš€

Express REST API

Build a complete API with Express

Install Express

Terminal
npm install express

Server Setup

server.js
require('dotenv').config();
const express = require('express');
const { connectDB } = require('./config/db');
const usersRouter = require('./routes/users');

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(express.json());

// Connect to MongoDB
let db;
connectDB().then(database => {
  db = database;
  
  // Make db available to routes
  app.use((req, res, next) => {
    req.db = db;
    next();
  });

  // Routes
  app.use('/api/users', usersRouter);

  // Start server
  app.listen(PORT, () => {
    console.log(`πŸš€ Server running on port ${PORT}`);
  });
});

User Routes

routes/users.js
const express = require('express');
const { ObjectId } = require('mongodb');
const router = express.Router();

// GET all users
router.get('/', async (req, res) => {
  try {
    const users = await req.db
      .collection('users')
      .find()
      .toArray();
    
    res.json(users);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// GET user by ID
router.get('/:id', async (req, res) => {
  try {
    const user = await req.db
      .collection('users')
      .findOne({ _id: new ObjectId(req.params.id) });
    
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// POST create user
router.post('/', async (req, res) => {
  try {
    const user = {
      ...req.body,
      createdAt: new Date()
    };
    
    const result = await req.db
      .collection('users')
      .insertOne(user);
    
    res.status(201).json({ 
      _id: result.insertedId,
      ...user 
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// PUT update user
router.put('/:id', async (req, res) => {
  try {
    const result = await req.db
      .collection('users')
      .updateOne(
        { _id: new ObjectId(req.params.id) },
        { 
          $set: { 
            ...req.body,
            updatedAt: new Date()
          }
        }
      );
    
    if (result.matchedCount === 0) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json({ message: 'User updated' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// DELETE user
router.delete('/:id', async (req, res) => {
  try {
    const result = await req.db
      .collection('users')
      .deleteOne({ _id: new ObjectId(req.params.id) });
    
    if (result.deletedCount === 0) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json({ message: 'User deleted' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

module.exports = router;
βœ… API Endpoints Ready!
  • GET /api/users - Get all users
  • GET /api/users/:id - Get user by ID
  • POST /api/users - Create user
  • PUT /api/users/:id - Update user
  • DELETE /api/users/:id - Delete user
🦫

Mongoose ODM

Object Data Modeling for MongoDB

Install Mongoose

Terminal
npm install mongoose

Connection & Schema

models/User.js
const mongoose = require('mongoose');

// Define Schema
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true
  },
  age: {
    type: Number,
    min: 0,
    max: 120
  },
  active: {
    type: Boolean,
    default: true
  }
}, {
  timestamps: true // Adds createdAt, updatedAt
});

// Create Model
const User = mongoose.model('User', userSchema);

module.exports = User;

Mongoose CRUD

Using Mongoose
const User = require('./models/User');

// Create
const user = new User({
  name: 'Alice Johnson',
  email: 'alice@example.com',
  age: 28
});
await user.save();

// OR using create
await User.create({
  name: 'Bob Smith',
  email: 'bob@example.com',
  age: 35
});

// Find
const users = await User.find({ active: true });
const user = await User.findOne({ email: 'alice@example.com' });
const user = await User.findById(id);

// Update
await User.updateOne(
  { email: 'alice@example.com' },
  { $set: { age: 29 } }
);

await User.findByIdAndUpdate(id, { age: 30 });

// Delete
await User.deleteOne({ email: 'alice@example.com' });
await User.findByIdAndDelete(id);
πŸ’‘ Mongoose Benefits
  • Schema validation
  • Type casting
  • Middleware (hooks)
  • Virtual properties
  • Built-in validation
  • Cleaner syntax
πŸ“Š

Aggregation Pipeline

Complex data operations

Basic Aggregation

Aggregation Example
async function aggregation() {
  const db = await connectDB();
  const collection = db.collection('users');

  const result = await collection.aggregate([
    // Match: age >= 25
    { $match: { age: { $gte: 25 } } },
    
    // Group by active status
    {
      $group: {
        _id: '$active',
        count: { $sum: 1 },
        avgAge: { $avg: '$age' }
      }
    },
    
    // Sort by count descending
    { $sort: { count: -1 } }
  ]).toArray();

  console.log(result);
}
⭐

Best Practices

Production-ready code

Connection Management

⚠️ Important Tips
  • Reuse Client: Create one client, reuse across app
  • Use Async/Await: Cleaner than callbacks
  • Error Handling: Always use try/catch
  • Environment Variables: Never hardcode credentials
  • Indexes: Create indexes for frequently queried fields
  • Connection Pool: Driver handles pooling automatically