Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS crash: Mongoose findById() does NOT throw error when document is NOT found

I tried researching for the cause of this problem; it is most likely a misunderstanding on my part of the way Mongoose works. I was experimenting with creating a CRUD backend in REST style. GET, PUT, POST all seem to work. However, I'm a bit at a loss with a problem with the DELETE verb.

The problem

I entered some fake data into mongo with Postman and all went well. So I copied the _id field of one my records and tried to DELETE. When I sent the DELETE request, the success message came through and the record was indeed removed from mongo. However, after deleting other records, I decided to try deleting a record with an _id of a document I had already deleted.

I sent a DELETE request to 'api/brothers/57280602953cff031f21ad9c'

Turns out NodeJS crashes!

Here's the relevant server code:

// DELETE a brother by id
app.delete('/api/brothers/:id', function(req, res) {

    Brother.findById(req.params.id, function(err, brother) {

      if (err) {
        // error finding brother
        res.json(err);

      } else {

        // remove record
        brother.remove(function(err, brother) {

          if (err) {
            // error removing!
            res.send(err);
          } else {

            // successful DELETE!
            res.json({
              message : "successfully deleted",
              brother : brother
            });
          }

        });
      }

    });


  });

Nodejs crashed and my console window returned the following:

TypeError: Cannot read property 'remove' of null
[nodemon] app crashed - waiting for file changes before starting...

Why wasn't an error thrown by Mongoose?

To my understanding, an error was not thrown because, had it been thrown, my if statement would have executed and returned the error to the user. If I enter a bogus id in the url then I get back an error, but if I paste in an _id of a record I already deleted, an error is NOT thrown, and execution moves on to the else block, and goes ahead removing a document that doesn't exist. Not even the .remove() seems to catch the error... the server just crashes.

So... my question is why? Does it have to do with Mongo casting the _id? Why isn't an error thrown? Why does the server crash.

Sort of a solution...

If I modify the if statement to not only catch for an error, but to also check for the existence of a brother returned from the findById() function, the error is returned to the user and the disaster is averted:

if (err || !brother) {
  // THIS WORKS
  res.json(brother);

 } else { ...

Again... why? Why if the brother obj is null does Mongoose even attempt to delete the document? And why does the server crash?

// I am using Express 4.13.4 and Mongoose 4.4.12

Thank you for your help, and pardon any novice ignorance.

like image 761
d8k_irf Avatar asked May 15 '16 03:05

d8k_irf


2 Answers

What you got is a Javascript error not a Mongoose one, you tried to call a method on null. foo = null; foo.bar(); yields the same error.

Finding 0 document is not an error, the action of finding was carried out but 0 thing was found.

Mongoose has an helper function, findOneAndRemove, you should use it, less code to write, less headaches:

app.delete('/api/brothers/:id', function(req, res) {
    Brother.findOneAndRemove({ _id: req.params.id }, function(err, brother, res) {

    });
});
like image 94
Shanoor Avatar answered Nov 16 '22 03:11

Shanoor


err is thrown in case of events like, unable to connect to database, invalid authentication, etc. But for queries it does throw any error as long as query is correct. In your case of query returns 0 rows it will simply call your callback with null, so you might want to put a check before using brother.

like image 29
Vikash Kesarwani Avatar answered Nov 16 '22 03:11

Vikash Kesarwani