ExpressJS - Database
Express.js - Integrating with a Database
Section titled “Express.js - Integrating with a Database”A dynamic web application needs a database to persist data. This tutorial will guide you through connecting a modern Express.js application to a MongoDB database using Mongoose, an elegant Object Data Modeling (ODM) library for Node.js.
Prerequisites and Setup
Section titled “Prerequisites and Setup”Before starting, ensure you have MongoDB installed and running on your system or have access to a cloud-based MongoDB service (like MongoDB Atlas).
- Install Mongoose:
npm install mongoose - Install
dotenvfor Environment Variables: This is a crucial best practice for managing sensitive data like database connection strings.npm install dotenv
Using Environment Variables
Section titled “Using Environment Variables”Create a file named .env in your project’s root directory. Never commit this file to version control.
# .env file
# Your MongoDB connection stringMONGO_URI=mongodb://127.0.0.1:27017/myModernAppDB
# Your application portPORT=3000Connecting to MongoDB
Section titled “Connecting to MongoDB”We will create a dedicated module to handle the database connection. This promotes clean code and separation of concerns.
config/db.js
Section titled “config/db.js”import mongoose from 'mongoose';
const connectDB = async () => { try { const conn = await mongoose.connect(process.env.MONGO_URI); console.log(`MongoDB Connected: ${conn.connection.host}`); } catch (error) { console.error(`Error: ${error.message}`); process.exit(1); // Exit process with failure }};
export default connectDB;In your main server file (server.js or app.js), you can now establish the connection.
import express from 'express';import dotenv from 'dotenv';import connectDB from './config/db.js';
// Load env varsdotenv.config();
// Connect to databaseconnectDB();
const app = express();
// ... rest of your app configurationDefining a Mongoose Schema and Model
Section titled “Defining a Mongoose Schema and Model”A Schema defines the structure of your documents within a collection, including field types and validation. A Model is a constructor compiled from a Schema definition, providing an interface to the database for creating, querying, updating, and deleting documents.
models/Person.js
Section titled “models/Person.js”import mongoose from 'mongoose';
const personSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Please provide a name'], trim: true }, age: { type: Number, required: [true, 'Please provide an age'], min: [0, 'Age cannot be negative'] }, nationality: { type: String, required: false, default: 'Not specified' }}, { timestamps: true // Automatically adds createdAt and updatedAt fields});
const Person = mongoose.model('Person', personSchema);
export default Person;Building a REST API with Async/Await
Section titled “Building a REST API with Async/Await”Modern JavaScript’s async/await syntax drastically simplifies asynchronous database operations, making code more readable and maintainable than old callback-based approaches. All database calls should be wrapped in try...catch blocks for robust error handling.
Creating a Document (POST /api/people)
Section titled “Creating a Document (POST /api/people)”// In your routes file (e.g., routes/people.js)
import Person from '../models/Person.js';
// @desc Create a new person// @route POST /api/peopleexport const createPerson = async (req, res) => { try { // req.body contains the parsed JSON from the request const newPerson = await Person.create(req.body); res.status(201).json({ success: true, data: newPerson }); } catch (error) { res.status(400).json({ success: false, error: error.message }); }};Reading Documents (GET /api/people)
Section titled “Reading Documents (GET /api/people)”// @desc Get all people// @route GET /api/peopleexport const getPeople = async (req, res) => { try { const people = await Person.find(); res.status(200).json({ success: true, count: people.length, data: people }); } catch (error) { res.status(500).json({ success: false, error: 'Server Error' }); }};Updating a Document (PATCH /api/people/:id)
Section titled “Updating a Document (PATCH /api/people/:id)”Note: We use PATCH for partial updates, which is a modern RESTful best practice. The old Model.update and Model.findByIdAndUpdate have been superseded. Modern Mongoose recommends fetching the document, updating it, and then saving it to trigger middleware, or using findOneAndUpdate with specific options.
// @desc Update a person// @route PATCH /api/people/:idexport const updatePerson = async (req, res) => { try { const person = await Person.findByIdAndUpdate( req.params.id, req.body, { new: true, runValidators: true } // Options );
if (!person) { return res.status(404).json({ success: false, error: 'Person not found' }); }
res.status(200).json({ success: true, data: person }); } catch (error) { res.status(400).json({ success: false, error: error.message }); }};Deleting a Document (DELETE /api/people/:id)
Section titled “Deleting a Document (DELETE /api/people/:id)”Note: The remove() method is deprecated. Use deleteOne(), deleteMany(), or findByIdAndDelete().
// @desc Delete a person// @route DELETE /api/people/:idexport const deletePerson = async (req, res) => { try { const person = await Person.findByIdAndDelete(req.params.id);
if (!person) { return res.status(404).json({ success: false, error: 'Person not found' }); }
res.status(200).json({ success: true, data: {} }); // Or send a confirmation message } catch (error) { res.status(500).json({ success: false, error: 'Server Error' }); }};Testing Your API
Section titled “Testing Your API”Use a tool like Postman, Insomnia, or a command-line tool like curl to test your endpoints. For example, to create a new person:
curl -X POST http://localhost:3000/api/people \ -H 'Content-Type: application/json' \ -d '{"name":"Jane Doe","age":30,"nationality":"Canadian"}'