Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async/await behaviour of mongoose findById

I have the following code:

const checkForRecord = async (id) => {

    let model = mongoose.model('User');

    let query = {}
    query.dummy = false; <== This is field is here to forcely cause an error, as it is not present on my User model.
    let result = await model.findById(id, query);

    console.log('Code reached here !!!');
    console.log(result);
}

I´m getting the following error:

(node:6680) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): CastError: Cast to ObjectId failed for value ...

My console.logs are not even being called.

Why is that error not being set to result, as my operation is async ?

I´ve tried both:

let result = await model.findById(id, query);

and

let result = await model.findById(id, query).exec();

Same behaviour.

like image 881
Mendes Avatar asked Mar 08 '23 17:03

Mendes


1 Answers

My console.logs are not even being called.

That's correct behavior. It's an async function and you're awaiting a function returning a promise. That means rejections are modelled as exceptions, terminating the checkForRecord function.

Why is that error not being set to result, as my operation is async ?

Because it's not a resolution value (which is what await gives you), it's a rejection/exception. It may help to look at what the de-sugared vesion of checkForRecord looks like, replacing async and await with their underlying promise operations:

// checkForRecord with async/await desugared to their underyling Promise operations
const checkForRecord = (id) => {

    let model = mongoose.model('User');

    let query = {};
    query.dummy = false; // <== To cause an error, this field is not used
    return model.findById(id, query).then(value => {
        let result = value;
        console.log('Code reached here !!!');
        console.log(result);
    });
};

As you can see, you don't get to the console.logs because they're in a resolution handler; but a rejection doesn't go to a resolution handler, it goes to a rejection handler.

To be clear: I'm not saying you need to change checkForRecord. I'm just showing you what the async/await becomes (in effect) at runtime.

Your checkForRecord is fine (other than a missing => and not having the comment on the query.dummy line commented). You'd use it like this in an async function:

try {
    checkForRecord(someId);
} catch (e) {
    // Handle the error here
}

...or like this if not in an async function:

checkForRecord(someId).catch(e => {
    // Handle the error here
});
like image 191
T.J. Crowder Avatar answered Mar 16 '23 13:03

T.J. Crowder