Geek Logbook

Tech sea log book

Handling Deletion of Bootcamps in a Node.js API with Mongoose

In this post, I’ll walk through the process of handling the deletion of bootcamps in a Node.js API using Mongoose. Recently, while working on a project, I encountered a TypeError when attempting to delete a bootcamp, and I’ll explain how I resolved it.

The Error

I had the following function for deleting bootcamps:

exports.deleteBootcamp = asyncHandler(async (req, res, next) => {
    const bootcamp = await Bootcamp.findById(req.params.id);

    if (!bootcamp) {
        return next(
            new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404)
        );
    }

    bootcamp.remove();  // Error occurs here

    res.status(200).json({ success: true, data: {} });
});

When attempting to delete a bootcamp, I encountered this error:

TypeError: bootcamp.remove is not a function
    at C:\Users\h\Documents\geeklogbook\devcamper_api\controllers\bootcamps.js:123:14
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Why Did This Error Happen?

The issue arises because the remove() method in Mongoose has been deprecated. In newer versions of Mongoose, you should use deleteOne() or deleteMany() instead of remove(). This change is important because Mongoose has shifted to a more consistent and simplified API for deleting documents.

The Solution

To fix the error, I replaced the bootcamp.remove() call with bootcamp.deleteOne(). Here’s the updated function:

exports.deleteBootcamp = asyncHandler(async (req, res, next) => {
    const bootcamp = await Bootcamp.findById(req.params.id);

    if (!bootcamp) {
        return next(
            new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404)
        );
    }

    await bootcamp.deleteOne();  // Use deleteOne() instead of remove()

    res.status(200).json({ success: true, data: {} });
});

This resolves the error and allows the deletion process to work as expected.

Hooking Into Bootcamp Deletion

In my API, I also needed to delete associated records (e.g., courses) when a bootcamp was removed. To do this, I was using the following pre-hook on the remove event:

BootcampSchema.pre('remove', async function(next) {
    console.log(`Courses being removed from bootcamp ${this._id}`);
    await this.model('Course').deleteMany({ bootcamp: this._id });
    next();
});

Since remove() was deprecated, this hook wouldn’t trigger anymore. I needed to update it to use deleteOne():

BootcampSchema.pre('deleteOne', { document: true }, async function(next) {
    console.log(`Courses being removed from bootcamp ${this._id}`);
    await this.model('Course').deleteMany({ bootcamp: this._id });
    next();
});

Now, whenever I delete a bootcamp, this hook ensures that all related courses are removed as well.

Conclusion

When working with Mongoose, it’s important to keep up with API changes. The remove() method is no longer available, so be sure to use deleteOne() or deleteMany() in your code. Additionally, remember to update any Mongoose middleware you may have that relies on the deprecated method.

By making these changes, I was able to get my bootcamp deletion functionality working properly while ensuring related data was cleaned up in the process.