Why is my Node.js api recognising a duplicate user from MongoDb but still adding an additional user?

I have included unique: true property for email while declaring the schema for user.

I am also using the mongoose.model.findOne(query, options) method of mongoose to check if user already exists and it throws the expected "User already exists" response in case of a duplicate email.

However, the user gets added to the DB anyway.

Below is the code for my API:

const express = require('express');
const mongoose = require('mongoose');
const router = express.Router();
const mongoUri = require('../../config/db.json').mongoUri;

const UserModel = require('../../models/user.js');

const options = {
	useNewUrlParser: true,
	useUnifiedTopology: true,
	useCreateIndex: true,
	useFindAndModify: false,
	autoIndex: false, // Don't build indexes
	poolSize: 5, // Maintain up to 10 socket connections
	serverSelectionTimeoutMS: 5000, // Keep trying to send operations for 5 seconds
	socketTimeoutMS: 5000, // Close sockets after 45 seconds of inactivity
	family: 4 // Use IPv4, skip trying IPv6
};

//@route    POST api/user
//@desc     Create User
//@access   private

router.post('/', async (req, res) => {
	const {
		email,
		name,
		password,
		permission
	} = req.body;
	try {
  
    mongoose.connect(mongoUri, options);
		
    var query = UserModel.where({
			email: email
		});

		query.findOne((err, existingUser) => {
			if (err) {
				return res.status(422).send(err);
			}
			if (existingUser) {
				return res.status(422).send({
					error: 'User already exists.'
				});
			}
		});
    
		const user = new UserModel({
			name,
			email,
			password,
			permission
		})
    
		const newUser = await user.save();
		return res.status(200).send(newUser);

	} catch (error) {
		return res.status(503).send(error);
	}
})

module.exports = router;

I am not able to figure out the solution using the documentation and I am unable to find a relevant answer.


I think this is as you create the newUser outside of an asynchronous block of code, so both of them will be executed, the check and creating a new user

so creating a new user does not wait until the email check is done

I suggest you to move creating the new user operation to be inside the call back of the email check

something like that

var query = UserModel.where({
    email: email
});

query.findOne((err, existingUser) => {
    if (err) {
        return res.status(422).send(err);
    }
    if (existingUser) {
        return res.status(422).send({
            error: 'User already exists.'
        });
    } else {
        // in the else condition, the email does not exist before in db, then create the user
        const user = new UserModel({
            name,
            email,
            password,
            permission
        })

        const newUser = await user.save();
        return res.status(200).send(newUser);
    }
});

hope it helps