MongoDB in Node.js
Working with MongoDB in Node.js can be done either with the official native MongoDB driver (for maximum speed and low abstraction) or with Mongoose (for schema validation, middleware, and business logic modeling).
Official Native MongoDB Driver
The native driver (mongodb) offers direct, low-overhead access to MongoDB wire protocol commands.
npm install mongodb
Connecting with MongoClient
import { MongoClient } from 'mongodb';
const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
const db = client.db('mydb');
const users = db.collection('users');
// Insert
const insertResult = await users.insertOne({
name: 'Alice',
email: '[email protected]',
createdAt: new Date(),
});
console.log('Inserted ID:', insertResult.insertedId);
// Query
const user = await users.findOne({ name: 'Alice' });
console.log('Found user:', user);
// Query multiple with cursor
const activeUsers = await users
.find({ active: true })
.sort({ createdAt: -1 })
.limit(10)
.toArray();
// Update
await users.updateOne(
{ _id: insertResult.insertedId },
{ $set: { active: true } }
);
// Delete
await users.deleteOne({ name: 'Alice' });
} finally {
await client.close();
}
}
run().catch(console.dir);
Mongoose (Object Data Modeling - ODM)
Mongoose provides schema validation, type casting, middleware hooks, and model relationships.
npm install mongoose
Connection Setup
import mongoose from 'mongoose';
const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/mydb';
await mongoose.connect(uri, {
autoIndex: true, // Build indexes automatically in dev (disable in heavy production)
});
Defining Schemas and Models
import mongoose, { Schema } from 'mongoose';
const userSchema = new Schema(
{
name: {
type: String,
required: [true, 'Name is required'],
trim: true,
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user',
},
age: {
type: Number,
min: 0,
max: 150,
},
},
{
timestamps: true, // Automatically manages createdAt and updatedAt
}
);
// Indexes
userSchema.index({ email: 1 });
// Instance method
userSchema.methods.sayHello = function () {
return `Hello, I'm ${this.name}!`;
};
// Compile into Model
export const User = mongoose.model('User', userSchema);
CRUD Operations with Mongoose
import { User } from './models/User.js';
// 1. Create
const user = await User.create({
name: 'Bob',
email: '[email protected]',
age: 28,
});
// 2. Read
const found = await User.findOne({ email: '[email protected]' });
const allUsers = await User.find({ age: { $gte: 18 } }).select('-__v').lean();
// 3. Update
const updated = await User.findOneAndUpdate(
{ email: '[email protected]' },
{ $set: { age: 29 } },
{ new: true, runValidators: true } // Return updated doc, run validations
);
// 4. Delete
await User.deleteOne({ email: '[email protected]' });
Native Driver vs. Mongoose
| Feature | Native Driver (mongodb) |
Mongoose |
|---|---|---|
| Abstraction Level | Low (Direct BSON/Wire protocol) | High (ODM with schemas & models) |
| Performance | Highest throughput, low memory | Slight overhead due to model wrapping |
| Validation | Manual or via MongoDB JSON Schema | Built-in declarative schema validators |
| Middleware / Hooks | Not supported | Pre/Post lifecycle hooks (pre('save')) |
| Population / Joins | $lookup aggregation pipeline |
.populate() virtual references |
Recommended Reading
SponsoredJavaScript Frameworks

