MongoDB is a popular NoSQL database known for its scalability, flexibility, and ease of use. Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js, providing a straightforward schema-based solution to model application data. This chapter will delve into integrating MongoDB with Mongoose in a Node.js application, covering everything from basic setup to advanced features. By the end of this chapter, you will have a comprehensive understanding of how to use MongoDB with Mongoose effectively.
MongoDB is a document-oriented NoSQL database that stores data in JSON-like documents. It is designed to handle a large amount of data with high performance and scalability. MongoDB is schema-less, allowing flexible data structures and making it suitable for various applications, including real-time analytics, content management systems, and more.
Mongoose is an ODM library that provides a schema-based solution to model application data for MongoDB. It offers powerful features such as schema validation, middleware, and easy-to-use methods for querying and manipulating data. Mongoose helps enforce data consistency and structure, making it easier to work with MongoDB.
To get started with MongoDB and Mongoose, you need to set up your development environment. Ensure you have Node.js and npm installed, and MongoDB running on your system.
mkdir mongoose-example
cd mongoose-example
npm init -y
npm install express mongoose body-parser
To connect to MongoDB using Mongoose, you need to establish a connection in your Node.js application.
// db/connection.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mongoose-example', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
console.log('Connected to MongoDB!');
});
module.exports = mongoose;
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('./db/connection');
const app = express();
app.use(bodyParser.json());
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
Schemas define the structure of documents within a collection in MongoDB. Models are constructors compiled from schemas that provide an interface to the database for creating, querying, updating, and deleting documents.
// models/user.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
age: {
type: Number,
min: 0
}
});
const User = mongoose.model('User', userSchema);
module.exports = User;
// app.js (continued)
const User = require('./models/user');
app.post('/users', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
} catch (err) {
res.status(400).json({ message: err.message });
}
});
// app.js (continued)
app.get('/users', async (req, res) => {
try {
const users = await User.find();
res.status(200).json(users);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
// app.js (continued)
app.put('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.status(200).json(user);
} catch (err) {
res.status(400).json({ message: err.message });
}
});
// app.js (continued)
app.delete('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.status(200).json({ message: 'User deleted successfully' });
} catch (err) {
res.status(500).json({ message: err.message });
}
});
Mongoose provides various methods for querying the database.
// Find users by age
app.get('/users/age/:age', async (req, res) => {
try {
const users = await User.find({ age: req.params.age });
res.status(200).json(users);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
// Paginate and sort users
app.get('/users/page/:page', async (req, res) => {
const page = parseInt(req.params.page, 10) || 1;
const limit = 10;
const skip = (page - 1) * limit;
try {
const users = await User.find().skip(skip).limit(limit).sort({ name: 1 });
res.status(200).json(users);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
Mongoose provides built-in validators and custom validation functions.
// models/user.js (continued)
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true,
match: /.+\@.+\..+/
},
age: {
type: Number,
min: 0,
max: 120
}
});
// models/user.js (continued)
userSchema.path('email').validate(async (email) => {
const emailCount = await mongoose.models.User.countDocuments({ email });
return !emailCount;
}, 'Email already exists');
Middleware functions are executed during the lifecycle of a document. They can be used for tasks such as validation, logging, and modifying documents.
// models/user.js (continued)
userSchema.pre('save', function (next) {
console.log(`User ${this.name} is being saved`);
next();
});
// models/user.js (continued)
userSchema.post('save', function (doc) {
console.log(`User ${doc.name} has been saved`);
});
Virtuals are document properties that do not persist to the database. They can be used for computed properties.
// models/user.js (continued)
userSchema.virtual('fullName').get(function () {
return `${this.firstName} ${this.lastName}`;
});
Population is a process of automatically replacing specified paths in the document with documents from other collections.
// models/user.js (continued)
const userSchema = new mongoose.Schema({
name: String,
email: String,
posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
});
// app.js (continued)
app.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id).populate('posts');
res.status(200).json(user);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
In this chapter, we covered integrating MongoDB with Mongoose in a Node.js application. We explored basic setup, schema and model definition, CRUD operations, querying, validations, middleware, and advanced features like virtuals and population. With the comprehensive information and practical examples provided, you should have a solid understanding of using MongoDB with Mongoose in your Node.js projects.Happy coding !❤️