Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update a record where _id = :id with Mongoose

I'm trying to update an existing record with Mongoose. The insert is OK but not the update.

Here is my snippet:

app.post('/submit', function(req, res) {

    var my_visit = new models.visits({
        date: req.body.visit_date,
        type: req.body.visit_type,
        agency: req.body.visit_agency,
        city: req.body.visit_city,
        url: req.body.visit_url,
        note: req.body.visit_note
    });

    // INSERT
    if(req.body.id == 0) {
        my_visit.save(function(err) {
            if(err) { throw err; }

            console.log('added visit');

            res.redirect('/');
        });
    } else { // UPDATE
        var upsertData = my_visit.toObject();

        console.log(req.body.id); // OK

        models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
            if(err) { throw err; }

            console.log('updated visit: '+ req.body.id);

            res.redirect('/');
        });
    }


})

The response is Mod on _id is not allowed.

I just want to update the line such as WHERE id = id in MySQL. I didn't find the right syntax.

like image 476
Syl Avatar asked Jun 22 '13 12:06

Syl


2 Answers

According to this question and this other one, the Mod on _id is not allowed occurs when one tries to update an object based on its id without deleting it first.

I also found this github issue which tries to explain a solution. It explicitly states:

Be careful to not use an existing model instance for the update clause (this won't work and can cause weird behavior like infinite loops). Also, ensure that the update clause does not have an _id property, which causes Mongo to return a "Mod on _id not allowed" error.

The solution, it seems, is to do the following:

var upsertData = my_visit.toObject();

console.log(req.body.id); // OK

delete upsertData._id;

models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
    if(err) { throw err; }
    //...
}

On a side note, you can probably rewrite your route to do both the create and update without the if-else clause. update() takes an extra option upsert, which, according to the docs:

upsert (boolean) whether to create the doc if it doesn't match (false)

like image 81
verybadalloc Avatar answered Sep 25 '22 14:09

verybadalloc


Here is my solution:

routes/router.js
router.patch('/user/:id', userController.updateUser)
exports.updateUser  =  async(req, res) => {



const  updates  =  Object.keys(req.body)

const  allowedUpdates  = ['name', 'email', 'password', 'age']

const  isValidOperation  =  updates.every((update) =>  allowedUpdates.includes(update))



if (!isValidOperation) {

return  res.status(400).send('Invalid updates!')

}



try {

const  user  =  await  UserModel.findByIdAndUpdate(req.params.id, req.body, { new:  true, runValidators:  true })



if (!user) {

return  res.status(404).send()

}



res.status(201).send(user)

} catch (error) {

res.status(400).send(error)

}

}
like image 25
Derya Cortuk Avatar answered Sep 24 '22 14:09

Derya Cortuk