skip to Main Content

I am creating a to-do list app, using node js, express, and mongoose.

now I am trying the delete item function, using a checkbox from a form to pass the item._id to the express,

My data type for to-do list items is like this:

const todoSchema = new mongoose.Schema({
    context: String
});


todoList> db.todolists.find()
[
  {
    _id: ObjectId("65085d9277578bec0a1b9415"),
    context: 'angry',
    __v: 0
  },
  {
    _id: ObjectId("65085db177578bec0a1b9421"),
    context: 'extremely angry',
    __v: 0
  },

here is my EJS code:

<form class="delete-form" action="/delete" method="POST">
    <div class="todobox">
        <input name="checkbox" value="<%=item._id%>" type="checkbox" onchange="this.form.submit()">
        <p>
            <%= item.context %>
        </p>
    </div>
</form>

and here is my JS code:

app.post("/delete", async(req, res) => {
    const checkedItem = req.body.checkbox;
    console.log(checkedItem);
    todolist.deleteOne({_id: checkedItem})
    .then(console.log(`Item (${checkedItem}) was deleted.`)).catch((err) => {
         console.log(err);
     });
    items = await todolist.find({}, { _id: 0, context: 1 });
    console.log(`now the to-do-list has ${items.length} items.`)
    res.redirect("/");
});

I print out the item._id ( req.body.checkbox ). and only got an empty String "".
catch the error:

CastError: Cast to ObjectId failed for value "" (type string) at path "_id" for model "todolist"
    at ObjectId.cast (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/schema/objectid.js:250:11)
    at SchemaType.applySetters (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/schematype.js:1220:12)
    at SchemaType.castForQuery (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/schematype.js:1632:15)
    at cast (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/cast.js:356:32)
    at Query.cast (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:4911:12)
    at Query._castConditions (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:2232:10)
    at model.Query._deleteOne (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:3021:8)
    at model.Query.exec (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:4430:28)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  stringValue: '""',
  messageFormat: undefined,
  kind: 'ObjectId',
  value: '',
  path: '_id',
  reason: BSONError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer
      at new ObjectId (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/bson/lib/bson.cjs:2055:23)
      at castObjectId (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/cast/objectid.js:25:12)
      at ObjectId.cast (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/schema/objectid.js:248:12)
      at SchemaType.applySetters (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/schematype.js:1220:12)
      at SchemaType.castForQuery (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/schematype.js:1632:15)
      at cast (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/cast.js:356:32)
      at Query.cast (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:4911:12)
      at Query._castConditions (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:2232:10)
      at model.Query._deleteOne (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:3021:8)
      at model.Query.exec (/Users/xuxiang/Documents/BACKEND/todoList-one/node_modules/mongoose/lib/query.js:4430:28),
  valueType: 'string',
  model: Model { todolist }
}

But when I pass item.context to express, it can successfully get the right result. for _id and __v, I can only got empty String "".

I also looked for the discussion of the course, asked ChatGPT, didn’t get a solution.

Thank you for your time and help.

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @nimrod serok. I changed my delete METHOD From

    app.post("/delete", async(req, res) => {
        ...
        items = await todolist.find({}, { _id: 0, context: 1 });
        ...
    });
    

    To:

    app.post("/delete", async(req, res) => {
        ...
        items = await todolist.find({}, { _id: 1, context: 1 });
        ...
    });
    

    This affected the req.body, and I can get the _id now. However I am still confused about why it will cause this issue.

    If anyone has an idea please kindly share, Thank @nimrod serok, and thank you very much.


  2. Main issue is checkedItem data type is String and while use in query it must be ObjectId

      // import 
        const { ObjectId } = require('mongodb')
    
    app.post("/delete", async (req, res) => {
        const checkedItem = req.body.checkbox;
        // check checkedItem is valid objectID or not
        if (!ObjectID.isvalid(checkedItem)) 
            res.status(400).send({ code: 400, success: false, error: 'invalid id' })
        console.log(checkedItem);
        todolist.deleteOne({ _id: new ObjectID(checkedItem) })
            .then(console.log(`Item (${checkedItem}) was deleted.`)).catch((err) => {
                console.log(err);
            });
        const items = await todolist.find({}, { _id: 1, context: 1 });
        console.log(`now the to-do-list has ${items.length} items.`)
        res.redirect("/");
    });
    

    other method with trycatch error handle

      // import 
        const { ObjectId } = require('mongodb')
    
        app.post("/delete", async (req, res) => {
            try {
                const checkedItem = req.body.checkbox;
                // check checkedItem is valid objectID or not
                if (!ObjectID.isvalid(checkedItem)) throw new Error('invalid id')
                console.log(checkedItem);
                todolist.deleteOne({ _id: new ObjectID(checkedItem) })
                    .then(console.log(`Item (${checkedItem}) was deleted.`)).catch((err) => {
                        console.log(err);
                    });
                const items = await todolist.find({}, { _id: 1, context: 1 });
                console.log(`now the to-do-list has ${items.length} items.`)
                res.redirect("/");
            } catch (error) {
                res.status(400).send({ code: 400, success: false, error: error.message })
                // or
                res.redirect("/400");
            }
        });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search