Episode 15 of 17
MongoDB with Node.js
Integrate MongoDB with Node.js using both the official MongoDB driver and Mongoose ODM. Learn how to connect, perform CRUD operations, build schemas, use middleware, handle errors, and structure a production-ready Express API backed by MongoDB.
Node.js and MongoDB are a natural pair — both work with JavaScript and JSON-like data. There are two main ways to use MongoDB with Node.js: the official MongoDB driver (low-level, direct control) and Mongoose (ODM with schemas, validation, and middleware). This episode covers both.
Setup
# Initialize a new Node.js project
mkdir mongo-node-app
cd mongo-node-app
npm init -y
# Install the MongoDB driver
npm install mongodb
# Install Mongoose (ODM)
npm install mongoose
# Install Express for the API
npm install express
Using the Official MongoDB Driver
Connecting
const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
async function connect() {
try {
await client.connect();
console.log('Connected to MongoDB');
const db = client.db('blogApp');
return db;
} catch (err) {
console.error('Connection failed:', err.message);
process.exit(1);
}
}
// Always close the connection when done
process.on('SIGINT', async () => {
await client.close();
process.exit(0);
});
CRUD with Native Driver
async function main() {
const db = await connect();
const users = db.collection('users');
// CREATE
const result = await users.insertOne({
name: 'Alice',
email: 'alice@example.com',
age: 28,
createdAt: new Date()
});
console.log('Inserted:', result.insertedId);
// READ
const user = await users.findOne({ email: 'alice@example.com' });
console.log('Found:', user);
const allDevs = await users.find({ role: 'developer' }).toArray();
console.log('Developers:', allDevs);
// UPDATE
await users.updateOne(
{ email: 'alice@example.com' },
{ $set: { age: 29 }, $inc: { loginCount: 1 } }
);
// DELETE
await users.deleteOne({ email: 'test@example.com' });
// COUNT
const count = await users.countDocuments({ role: 'developer' });
console.log('Developer count:', count);
}
main();
Using Mongoose (Recommended for Most Projects)
Connecting with Mongoose
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/blogApp', {
// Mongoose 7+ doesn't need these options
})
.then(() => console.log('Mongoose connected'))
.catch(err => console.error('Connection error:', err));
Defining Schemas and Models
const { Schema, model } = require('mongoose');
// Define a schema
const userSchema = new Schema({
name: {
type: String,
required: [true, 'Name is required'],
trim: true,
minlength: 2,
maxlength: 100
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, 'Invalid email format']
},
age: {
type: Number,
min: 0,
max: 150
},
role: {
type: String,
enum: ['user', 'admin', 'moderator'],
default: 'user'
},
tags: [String],
address: {
street: String,
city: String,
state: String,
zip: String
},
isActive: {
type: Boolean,
default: true
}
}, {
timestamps: true // Adds createdAt and updatedAt automatically
});
// Create the model
const User = model('User', userSchema);
Mongoose CRUD Operations
// CREATE
const user = await User.create({
name: 'Alice',
email: 'alice@example.com',
age: 28,
role: 'user'
});
// READ
const alice = await User.findOne({ email: 'alice@example.com' });
const users = await User.find({ role: 'user' }).sort({ name: 1 }).limit(10);
const userById = await User.findById('65a1b2c3d4e5f6a7b8c9d0e1');
// UPDATE
await User.findByIdAndUpdate(userId, {
$set: { name: 'Alice Updated' }
}, { new: true, runValidators: true });
// DELETE
await User.findByIdAndDelete(userId);
await User.deleteMany({ isActive: false });
Mongoose Middleware (Hooks)
// Pre-save middleware — runs before saving
userSchema.pre('save', function(next) {
// Hash password before saving
if (this.isModified('password')) {
this.password = hashPassword(this.password);
}
next();
});
// Post-save middleware — runs after saving
userSchema.post('save', function(doc) {
console.log('User saved:', doc.email);
});
// Pre-find middleware
userSchema.pre('find', function() {
// Only return active users by default
this.where({ isActive: true });
});
Express API with MongoDB
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.use(express.json());
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/blogApp');
// User model (from above)
const User = require('./models/User');
// GET all users
app.get('/api/users', async (req, res) => {
try {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const skip = (page - 1) * limit;
const users = await User.find()
.select('-password')
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit);
const total = await User.countDocuments();
res.json({
data: users,
pagination: { page, limit, total, pages: Math.ceil(total / limit) }
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// POST create user
app.post('/api/users', async (req, res) => {
try {
const user = await User.create(req.body);
res.status(201).json(user);
} catch (err) {
if (err.code === 11000) {
return res.status(409).json({ error: 'Email already exists' });
}
res.status(400).json({ error: err.message });
}
});
// GET single user
app.get('/api/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// PUT update user
app.put('/api/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true }
);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// DELETE user
app.delete('/api/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json({ message: 'User deleted' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
What's Next
You now have a complete Node.js API backed by MongoDB. In the next episode, we'll integrate MongoDB with PHP — connecting, performing CRUD, and using the MongoDB PHP library for server-side applications.