Mongoose find() callback not actually being called

Viewed 1382

I'm new to Mongoose and also using async/await. Right now I have a Mongoose schema, with a static method, like so:

const userSchema = new Schema({
    username: String,
    pass: String
});


userSchema.statics.checkExist = async function(username){
    return await this.findOne({username: username}, function(err, res){
        if(err){
            return err;
        }
        if(res){
            return true;
        }
        else{
            return false;
        }
    })
}

The static method checkExist() is supposed to take in a username, and check if a document already exists with the same username. If it does, it should return true, otherwise false. I use it in my NodeJS/Express server like so:

router.post('/auth/login', async (req, res) =>{
    let username = req.body.username;

    let existBool = await UserModel.checkExist(username);

    console.log(existBool);
    res.send({'hash': existBool});
});

I expect existBool to be the true/false boolean. Instead, checkExist() doesn't seem to call the callback function at all. Instead it returns the result of findOne(), which is an object that has the matching username field. What am I doing wrong here?

2 Answers

You're mixing callbacks with async/await which uses promises. You're also misunderstanding how the callbacks work; The result of the await isn't the return value of the callback, it's the return value of findOne().

await is used hold until an async function returns a promise, it then "unwraps" that promise into a variable. If the findOne() method supports promises, you should not be using the callbacks at all.

let result = await this.findOne({username: username})

The reason async/await is so powerful is because it removes the need for .then() promise syntax and lets you write sequential code again, but have it handle async behaviour. It lets you use loops and, most importantly, lets you use try/catch statements to handle errors again.

try {
  let result = await this.findOne({username: username})
} catch(ex) {
  // handle exception here
}

This is the schema

const mongoose = require('mongoose');

var userSchema = new mongoose.Schema({
    _id: mongoose.Schema.Types.ObjectId,
    username: {
        type: String,
        required: true,
        unique: true
    },
    password: {
        type: String,
        required: true
    }
}, {
        timestamps: { createdAt: true, updatedAt: true },
        collection: 'users'
    });

module.exports = mongoose.model("User", userSchema);

The Router end point is below

// API endpoint to insert new user.
router.post('/insertUser', function (req, res, next) {
    let request = req.body;
    let userSchema = new UserModel({
        _id: new mongoose.Types.ObjectId(),
        username: request.username,
        password: request.password
    }); `enter code here`

    if (!userSchema.username) {
        res.status(200).json({ success: false, msg: 'Username can\'t be empty' });
    } else if (!userSchema.password) {
        res.status(200).json({ success: false, msg: 'Password can\'t be empty' });
    } else {
        // If username is not unique in schema do check this...
        UserModel.findOne({ username: userSchema.username }).exec()
            .then(result => {
                if (result == null) {
                    //Here the User is added
                    userSchema.save().then(result => {
                        res.status(200).json({ success: true, msg: 'User Added' });
                    }).catch(exception => {
                        console.log(exception);
                        res.status(200).json({ success: false, msg: 'Something went wrong' });
                    });
                } else {
                    res.status(200).json({ success: false, msg: 'Username already taken' });
                }
            }).catch(exception => {
                console.log(exception);
                res.status(200).json({ success: false, msg: 'Something went wrong' });
            });
    }

});
Related