Search code examples
javascriptnode.jsmongodbmerninternal-server-error

Cannot perform CRUD (DELETE operation) on MongoDB (MERN stack)


I’m working on a MERN stack “to-do list” application which performs CRUD operations. I could successfully implement “adding task to the database” functionality. However, for “removing task” I’m facing with Internal Server Error that I can’t fix although I’ve done research and tried multiple solutions.

I’m sharing related code snippets and I hope someone can help me a bit.

In my client folder, Task.jsx component: *WORKING CODE

function Task({ task }) {
    const { _id, title, description, completed } = task;
    const { dispatch } = useContext(TaskContext);
    const { userToken } = useContext(TokenContext);

    const handleRemove = async (e) => {
        e.preventDefault();
        console.log("Task ID to remove:", _id);
    
        try {
            const res = await axios.get("/task/removeTask", {
                headers: {
                    Authorization: `Bearer ${userToken}`
                },
                params: {
                    _id
                }
            });
            console.log("Task deletion response:", res.data);
            dispatch({
                type: "REMOVE_TASK",
                _id
            });
        } catch (error) {
            console.error("Error removing task:", error);
            // Handle error state or display an error message to the user
        }
    }

taskReducer.js file: *WORKING CODE

function taskReducer(tasks, action) {
    console.log("taskreducer");
    switch (action.type) {
        // eslint-disable-next-line no-lone-blocks
        case "ADD_TASK": {
            return [
                ...tasks,
                {
                    _id: action._id,
                    title: action.title,
                    description: action.description,
                    completed: false
                }
            ]
        }
        case "SET_TASK": {
            return action.payload
        }
        case "REMOVE_TASK": {
            console.log("Tasks before removal:", tasks);
            const updatedTasks = tasks.filter((task) => task._id !== action._id);
            console.log("Tasks after removal:", updatedTasks);
            return updatedTasks;
        }

In my server folder, taskController.js file: *WORKING CODE

import taskModel from "../models/taskModel.js";
import userModel from "../models/userModel.js";
import dotenv from "dotenv";
import mongoose from "mongoose";
dotenv.config();

const addTask = async (req, res) => {
    const { _id, title, description } = req.body;
    const userId = req.user.id;

    const user = await userModel.find({_id: userId});
    if (!user) {
        return res.status(404).json({ message: "User not found" });
    }

    const taskId = _id ? mongoose.Types.ObjectId(_id) : new mongoose.Types.ObjectId();

    console.log("Task to be saved:", { taskId, title, description, completed: false, userId });

    const newTask = new taskModel({ _id: taskId, title, description, completed: false, userId })

    newTask.save()
        .then((savedTask) => {
            return (res.status(200).json({ message: "Task added successfully", task: savedTask }))
        })
        .catch((error) => {
            return (
                res.status(500).json({ message: error.message })
            )
        }
        )
}

const removeTask = (req, res) => {
    const { _id } = req.query;

    console.log("Task ID to remove:", _id); // Log the ID being used for deletion

    taskModel.findByIdAndDelete( _id )
        .then((deletedTask) => {
            if (!deletedTask) {
                return res.status(404).json({ message: "Task not found" });
            }
            console.log("Deleted task:", deletedTask); // Log the deleted task
            return res.status(200).json({ message: "Task deleted successfully" });
        })
        .catch((error) => {
            console.error("Error deleting task:", error); // Log any errors
            return res.status(500).json({ message: "Internal server error" });
        });
}

const getTask = (req, res) => {
    taskModel.find({ userId: req.user.id })
        .lean() // Convert Mongoose documents to plain JavaScript objects
        .then((data) => res.status(200).json(data))
        .catch((error) => res.status(501).json({ message: error.message }))
}

export { addTask, getTask, removeTask }

taskRoute.js file: *WORKING CODE

router.post("/addTask", requireAuth, addTask)
router.get("/getTask", requireAuth, getTask)
router.get("/removeTask", requireAuth, removeTask)

Only removeTask function doesn’t work.

When I add a task, this is the response I’m getting on my browser console:

XHR OPTIONS http://localhost:8000/api/task/addTask[HTTP/1.1 204 No Content 6ms]
XHR POST http://localhost:8000/api/task/addTask[HTTP/1.1 200 OK 468ms]

When I click on the delete button to remove a task, this is the response:

Task ID to remove: 662e7dc365cc6fb9a0e14ed7 // matches the database
XHR OPTIONS http://localhost:8000/api/task/removeTask[HTTP/1.1 204 No Content 10ms]
XHR GET http://localhost:8000/api/task/removeTask[HTTP/1.1 500 Internal Server Error 1ms]
Error removing task: message: “Request failed with status code 500”, name: “AxiosError”, code: “ERR_BAD_RESPONSE”, config: {…}, request: XMLHttpRequest, response: {…} }

​I’ve also tried router.delete("/removeTask") and axios.delete("/task/removeTask") instead of GET method but nothing changed.

I hope you can enlight me a bit about the issue because I’m stucked up on this for a couple of days. Thanks.

EDIT:

Error removing task: 
Object { stack: "AxiosError@http://localhost:3000/static/js/bundle.js:64350:18
settle@http://localhost:3000/static/js/bundle.js:65001:12
onloadend@http://localhost:3000/static/js/bundle.js:63696:66
EventHandlerNonNull*dispatchXhrRequest@http://localhost:3000/static/js/bundle.js:63709:7
./node_modules/axios/lib/adapters/xhr.js/__WEBPACK_DEFAULT_EXPORT__<@http://localhost:3000/static/js/bundle.js:63651:10
dispatchRequest@http://localhost:3000/static/js/bundle.js:64830:10
request@http://localhost:3000/static/js/bundle.js:64267:77
./node_modules/axios/lib/core/Axios.js/forEachMethodNoData/Axios.prototype[method]@http://localhost:3000/static/js/bundle.js:64289:17
wrap@http://localhost:3000/static/js/bundle.js:65402:15
handleRemove@http://localhost:3000/static/js/bundle.js:1828:81
callCallback@http://localhost:3000/static/js/bundle.js:29974:18
invokeGuardedCallbackDev@http://localhost:3000/static/js/bundle.js:30018:20
invokeGuardedCallback@http://localhost:3000/static/js/bundle.js:30075:35
invokeGuardedCallbackAndCatchFirstError@http://localhost:3000/static/js/bundle.js:30089:29
executeDispatch@http://localhost:3000/static/js/bundle.js:34233:46
processDispatchQueueItemsInOrder@http://localhost:3000/static/js/bundle.js:34259:26
processDispatchQueue@http://localhost:3000/static/js/bundle.js:34270:41
dispatchEventsForPlugins@http://localhost:3000/static/js/bundle.js:34279:27
./node_modules/react-dom/cjs/react-dom.development.js/dispatchEventForPluginEventSystem/<@http://localhost:3000/static/js/bundle.js:34439:16
batchedUpdates$1@http://localhost:3000/static/js/bundle.js:48831:16
batchedUpdates@http://localhost:3000/static/js/bundle.js:29822:16
dispatchEventForPluginEventSystem@http://localhost:3000/static/js/bundle.js:34438:21
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay@http://localhost:3000/static/js/bundle.js:31944:42
dispatchEvent@http://localhost:3000/static/js/bundle.js:31938:88
dispatchDiscreteEvent@http://localhost:3000/static/js/bundle.js:31915:22
EventListener.handleEvent*addEventBubbleListener@http://localhost:3000/static/js/bundle.js:32137:14
addTrappedEventListener@http://localhost:3000/static/js/bundle.js:34361:33
listenToNativeEvent@http://localhost:3000/static/js/bundle.js:34305:30
./node_modules/react-dom/cjs/react-dom.development.js/listenToAllSupportedEvents/<@http://localhost:3000/static/js/bundle.js:34316:34
listenToAllSupportedEvents@http://localhost:3000/static/js/bundle.js:34311:25
createRoot@http://localhost:3000/static/js/bundle.js:51594:33
createRoot$1@http://localhost:3000/static/js/bundle.js:51940:14
./node_modules/react-dom/client.js/exports.createRoot@http://localhost:3000/static/js/bundle.js:52016:16
./src/index.js@http://localhost:3000/static/js/bundle.js:2227:60
options.factory@http://localhost:3000/static/js/bundle.js:68791:31
__webpack_require__@http://localhost:3000/static/js/bundle.js:68237:33
@http://localhost:3000/static/js/bundle.js:69373:56
@http://localhost:3000/static/js/bundle.js:69375:12
", 
message: "Request failed with status code 500", 
name: "AxiosError", 
code: "ERR_BAD_RESPONSE", 
config: {…}, 
request: XMLHttpRequest, 
response: {…} 
}

EDIT #2:

I've removed requireAuth from router.get("/removeTask", requireAuth, removeTask) in taskRoute.js file. My server console logs are back.

Here is the full error log on my browser console:

Task ID to remove: 662e7dc365cc6fb9a0e14ed7 Task.jsx:14

XHR OPTIONS http://localhost:8000/api/task/removeTask?_id=662e7dc365cc6fb9a0e14ed7 [HTTP/1.1 204 No Content 9ms]

XHR GET http://localhost:8000/api/task/removeTask?_id=662e7dc365cc6fb9a0e14ed7 [HTTP/1.1 500 Internal Server Error 25ms]

Error removing task: 
Object { stack: "AxiosError@http://localhost:3000/static/js/bundle.js:64350:18\nsettle@http://localhost:3000/static/js/bundle.js:65001:12\nonloadend@http://localhost:3000/static/js/bundle.js:63696:66\nEventHandlerNonNull*dispatchXhrRequest@http://localhost:3000/static/js/bundle.js:63709:7\n./node_modules/axios/lib/adapters/xhr.js/__WEBPACK_DEFAULT_EXPORT__<@http://localhost:3000/static/js/bundle.js:63651:10\ndispatchRequest@http://localhost:3000/static/js/bundle.js:64830:10\nrequest@http://localhost:3000/static/js/bundle.js:64267:77\n./node_modules/axios/lib/core/Axios.js/forEachMethodNoData/Axios.prototype[method]@http://localhost:3000/static/js/bundle.js:64289:17\nwrap@http://localhost:3000/static/js/bundle.js:65402:15\nhandleRemove@http://localhost:3000/static/js/bundle.js:1828:81\ncallCallback@http://localhost:3000/static/js/bundle.js:29974:18\ninvokeGuardedCallbackDev@http://localhost:3000/static/js/bundle.js:30018:20\ninvokeGuardedCallback@http://localhost:3000/static/js/bundle.js:30075:35\ninvokeGuardedCallbackAndCatchFirstError@http://localhost:3000/static/js/bundle.js:30089:29\nexecuteDispatch@http://localhost:3000/static/js/bundle.js:34233:46\nprocessDispatchQueueItemsInOrder@http://localhost:3000/static/js/bundle.js:34259:26\nprocessDispatchQueue@http://localhost:3000/static/js/bundle.js:34270:41\ndispatchEventsForPlugins@http://localhost:3000/static/js/bundle.js:34279:27\n./node_modules/react-dom/cjs/react-dom.development.js/dispatchEventForPluginEventSystem/<@http://localhost:3000/static/js/bundle.js:34439:16\nbatchedUpdates$1@http://localhost:3000/static/js/bundle.js:48831:16\nbatchedUpdates@http://localhost:3000/static/js/bundle.js:29822:16\ndispatchEventForPluginEventSystem@http://localhost:3000/static/js/bundle.js:34438:21\ndispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay@http://localhost:3000/static/js/bundle.js:31944:42\ndispatchEvent@http://localhost:3000/static/js/bundle.js:31938:88\ndispatchDiscreteEvent@http://localhost:3000/static/js/bundle.js:31915:22\n", 
message: "Request failed with status code 500", 
name: "AxiosError", 
code: "ERR_BAD_RESPONSE", 
config: {…}, 
request: XMLHttpRequest, 
response: {…} }

Here is the full error log on my server console:

Task ID to remove: undefined
Error deleting task: CastError: Cast to ObjectId failed for value "{ _id: undefined }" (type Object) at path "_id" for model "Task"
    at model.Query.exec (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\query.js:4913:21)
    at Query.then (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\query.js:5012:15)
    at removeTask (file:///C:/Users/Rumeysa/Downloads/mern-todo-app-master/server-side/controllers/taskController.js:40:10)
    at Layer.handle [as handle_request] (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\route.js:144:13)
    at Route.dispatch (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\route.js:114:3)
    at Layer.handle [as handle_request] (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\index.js:284:15  
    at Function.process_params (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\index.js:346:12)
    at next (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\express\lib\router\index.js:280:10) {
  messageFormat: undefined,
  stringValue: '"{ _id: undefined }"',
  kind: 'ObjectId',
  value: { _id: undefined },
  path: '_id',
  reason: BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer
      at new BSONTypeError (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\bson\lib\error.js:41:28)
      at new ObjectId (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\bson\lib\objectid.js:67:23)
      at castObjectId (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\cast\objectid.js:25:12)
      at ObjectId.cast (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\schema\objectid.js:246:12)
      at SchemaType.applySetters (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\schematype.js:1201:12)
      at SchemaType._castForQuery (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\schematype.js:1648:15)
      at SchemaType.castForQuery (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\schematype.js:1636:15)
      at SchemaType.castForQueryWrapper (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\schematype.js:1612:20)
      at cast (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\cast.js:293:34)      at Query.cast (C:\Users\Rumeysa\Downloads\mern-todo-app-master\server-side\node_modules\mongoose\lib\query.js:5341:12),
  valueType: 'Object'
}

Here's the schema on MongoDB:

_id: ObjectId('662e7dc365cc6fb9a0e14ed7')
title: "Add TEST data"
description: "Add data"
userId: "6629874938bc9859f2505388"
completed: false
createdAt: 2024-04-28T16:48:03.875+00:00
updatedAt: 2024-04-28T16:48:03.875+00:00
__v: 0

FINAL EDIT:

Please check the answer. I've edited my code above with the current modifications that fixed the errors I encountered. It is how it looks right now while the app is seamlessly working.


Solution

  • After EDIT #2 I have modified the following statements as well and "removing task" fuctionality started to seamlessly work.

    In taskController.js file:

    From const { _id } = req.body to const { _id } = req.query;

    From taskModel.findByIdAndDelete({ _id }) to taskModel.findByIdAndDelete( _id )

    I also have added requireAuth back to router.get("/removeTask", removeTask) and everything works as expected including server console logs.

    Why requireAuth was a problem so far is because I've defined userToken in const res = await axios.get("/task/removeTask", { headers: { Authorization: 'Bearer ${userToken}' }, in Task.js wrong!

    I wrote const { userToken } = useContext(TaskContext); while correct statement would be const { userToken } = useContext(TokenContext);

    I would like to thank user @we-do-the-best-for-you for helping me to debug the issue and leading me to the solution.

    I'm editing all the code in my question post above with correct changes to reveal fixed code that makes the app work.