How to Handle Errors in MongoDB Operations using NodeJS?

Handling errors in MongoDB operations is important for ensuring the stability and reliability of your Node.js application. In this article, we’ll dive deep into error-handling techniques specifically for MongoDB operations in Node.js. We’ll cover topics such as error types, error-handling strategies, and best practices for handling errors effectively.

Prerequisites :

Steps to Create the Project

Step 1: Create a new directory for your project:

mkdir server
cd server

Step 2: Initialize a new Node.js project:

npm init -y

Step 3. Install Dependencies

npm install express mongoose cors

Step 4. Create the directory structure:

mkdir controller middlewares models route

Dependencies

"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"mongodb": "^6.6.1",
"mongoose": "^8.3.4"
}

Project Stucture

project structure

MongoDB Error Types

  • Network Errors: These errors occur when there are issues with the network connection between your Node.js application and the MongoDB server. Examples include connection timeouts, network failures, or server unavailability.
  • Validation Errors: MongoDB enforces schema validation, and errors can occur when data doesn’t meet the defined schema requirements, such as missing required fields or data type mismatches.
  • Duplicate Key Errors: MongoDB throws errors when attempting to insert or update a document with a duplicate key value in a unique index.
  • Write Errors: These errors occur during write operations such as inserts, updates, or deletes. Examples include write conflicts, write concern failures, or write operations exceeding the server’s limitations.
  • Query Errors: Errors can also arise from incorrect query syntax, invalid aggregation pipeline stages, or unsupported operations.

Error Handling Strategies

Now that we understand the types of errors, let’s explore some effective error handling strategies for MongoDB operations in Node.js:

1. Use Try-Catch Blocks

JavaScript
//asuming u have setup the express sever and connected to mongodb

try {
    const result = await collection.insertOne({ name: 'gfg' });
    console.log('Document inserted:', result.insertedId);
} catch (error) {
    console.error('Error inserting document:', error);
}

2. Handle Asynchronous Errors

For asynchronous operations, handle errors in the catch block of the Promise.

JavaScript
collection.insertOne({ name: 'gfg' })
    .then(result => console.log('Document inserted:', result.insertedId))
    .catch(error => console.error('Error inserting document:', error));

3. Use Error Events

MongoDB drivers for Node.js emit error events that you can listen to for handling errors globally. For example:

JavaScript
const client = new MongoClient(uri, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
});

client.on("error", (err) => {
    console.error("MongoDB connection error:", err);
});

client
    .connect()
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error("Error connecting to MongoDB:", err));

4. Handle Specific Error Types

Differentiate between error types and handle them accordingly. For example, handle network errors separately from validation errors or duplicate key errors.

5. Implement Retry Logic

In case of transient errors like network timeouts, implement retry logic with exponential backoff to retry failed operations.

6. Log Errors

Always log errors with relevant information such as error messages, stack traces, and context to facilitate debugging and troubleshooting.

Handling Query Error:

First, start your MongoDB database, and then we’ll connect to MongoDB in the Express server. We’ll start by posting data to a database named “my_database.”

Before starting the server start the MongoDB and after succesful setup start the server and make a get request with the following url.

localhost:3001/api/retrieveData
JavaScript
// index.js

import express from "express";
import connectDB from "./db.js";
import errorHandler from "./middlewares/errorhandler.js";
import corsMiddleware from "./middlewares/cors.js";
import router from "./route/gfgroutes.js";

const app = express();

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

// Routes
app.use("/api", router);

app.get("/", (req, res) => {
    res.send("Welcome to the server");
});

// Error Handling Middleware
app.use(errorHandler);

// Start the server
const PORT = process.env.PORT || 3001;
connectDB()
    .then(() => {
        app.listen(PORT, () => {
            console.log(`Server is running on port ${PORT}`);
        });
    })
    .catch((err) => {
        console.error("Failed to start server:", err);
    });
JavaScript
// db.js

import mongoose from "mongoose";

const connectDB = async () => {
    try {
        await mongoose.connect("mongodb://127.0.0.1:27017/my_database", {});
        console.log("MongoDB connected");
    } catch (error) {
        console.error("MongoDB connection error:", error);
        throw new Error("Unable to connect to the database");
    }
};

export default connectDB;
JavaScript
// route/gfgRoutes.js

import express from "express";
import { createDummyData, retrieveData }
    from "../controller/gfgcontroller.js";

const router = express.Router();

router.post("/", createDummyData);
router.get("/retrieveData", retrieveData);

export default router;
JavaScript
// models/gfgModel.js

import mongoose from "mongoose";

const gfgSchema = new mongoose.Schema({
    name: String,
    email: String,
});

const GfgModel = mongoose.model("gfg", gfgSchema);

export default GfgModel;
JavaScript
// middlewares/errorhandler.js

const errorHandler = (err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send("Something broke!");
};

export default errorHandler;
JavaScript
// middlewares/cors.js

import cors from "cors";

const corsOptions = {
    origin: "*",
};

const corsMiddleware = cors(corsOptions);

export default corsMiddleware;
JavaScript
// middlewares/cors.js

import cors from "cors";

const corsOptions = {
    origin: "*",
};

const corsMiddleware = cors(corsOptions);

export default corsMiddleware;

import GfgModel from "../models/gfgModel.js";

// Store a dummy record
export const createDummyData = async (req, res) => {
    try {
        const dummyData = await GfgModel.create({
            name: "John Doe",
            email: "johndoe@example.com",
        });
        console.log("Dummy data stored in MongoDB:", dummyData);
        res.sendStatus(200);
    } catch (error) {
        console.error("Error storing dummy data in MongoDB:", error);
        res.status(500).send("Error storing dummy data in MongoDB");
    }
};

// Retrieve data from MongoDB
export const retrieveData = async (req, res) => {
    try {
        const data = await GfgModel.find({ name: "John Doe" });
        if (!data || data.length === 0) {
            throw new Error("Data not found or query returned empty result");
        }
        console.log("Retrieved data from MongoDB:", data);
        res.json(data);
    } catch (error) {
        console.error("Error retrieving data from MongoDB:", error);
        res.status(500).send("Error retrieving data from MongoDB");
    }
};

inserted data successfully to our my_database

Now querying to the get method for the route “/retrieveData” we get the following error.

thrown error as the fields dosen’t exist

Querying with existing fields to the database results in the following output:

valid query result.



Most Common Query Errors

  • Syntax Errors: Incorrect syntax in the query, like missing brackets or quotes.
  • Invalid Field Names: Querying for non-existent fields or using incorrect field names.
  • Invalid Operator Usage: Misusing MongoDB operators in the query.
  • Data Type Mismatches: Using operators with incompatible data types in the query.
  • Index Errors: Querying unindexed fields or using unoptimized queries for performance.

Best Practices for Error Handling

  • Data Validation: Always validate data against the schema before performing MongoDB operations to ensure data integrity and prevent validation errors.
  • Transactional Operations: Use MongoDB transactions for operations that require atomicity to ensure either all operations succeed or none do, maintaining data consistency.
  • Error Recovery: Implement mechanisms like retries, fallbacks, or error notifications to handle failures gracefully and improve application reliability.
  • Error Monitoring: Continuously monitor MongoDB operations for errors. Analyzing error patterns helps identify and address common issues, improving error handling.
  • Documentation: Document error handling practices thoroughly, detailing common errors, mitigation strategies, and escalation procedures. This aids in troubleshooting and training, ensuring consistency and efficiency.


Contact Us