0

I am using node and mongoDB to create a backend service.

I do have a schema as follows :

const UserSchema = new Schema({
    name : {
        type : String,
        required : true
    },
    email : {
        type : String,
        required : true
    },
    phoneNo : {
        type : Number,
        required : true
    },
    password : {
        type : String,
        required : true
    },
    avatar : {
        type : String
    },
    date  : {
        type : Date,
        default : Date.now()
    }
})

Now I want to validate whether the phone no and email exists or not. For this check I have the following code snippet :


User.findOne({ email : req.body.email })
        .then(user => {
            if (user){ 
                errors.email = 'Email already exists';
                return res.status(400).json(errors);
            } else {
                User.findOne( {phoneNo : req.body.phoneNo})
                .then (user => {
                    if(user) {
                        errors.phoneNo = 'Phone no already exists';
                        return res.status(400).json(errors);
                    }
                    else {
                    .....

So I am using nested promise. I believe this is not a good practice to go on. But I need to show different validation messages for different points. Can this be achievable in any simpler way ?

Soumya Kanti Naskar
  • 1,021
  • 3
  • 16
  • 29

2 Answers2

1

You could use async/await that will make your code simpler and easier to reason about.

async function main() {
    const existingByEmail = await User.findOne({ email: req.body.email });

    if (existingByEmail) {
        errors.email = "Email already exists";
        return res.status(400).json(errors);
    }

    const existingByPhone = await User.findOne({ phoneNo: req.body.phoneNo });

    if (existingByPhone) {
        errors.phoneNo = "Phone no already exists";
        return res.status(400).json(errors);
    }
}
Dan Starns
  • 3,765
  • 1
  • 10
  • 28
1

You can set email and phoneNo to be unique (recommended) and check for duplication error handled by mongoose.

    email : {
        type : String,
        required : true,
        unique : true // add unique option
    },
    phoneNo : {
        type : Number,
        required : true,
        unique : true // add unique option
    },

This package mongoose-unique-validator will return the field that trigger duplication error. But you can also handle the duplication error by yourself, as suggested here, but you will have to check the index by yourself to see which field caused duplication

Above approaches will handle duplication errors when you insert/update a document, so you won't need your current validation code.

For the purpose of improving your validation flow, if you want to avoid nested Promises, you can call them at the same time using Promise.all()

/* without async/await */

Promise.all([
  User.findOne({ email: req.body.email }).exec(),
  User.findOne({ phoneNo: req.body.phoneNo }).exec()
]).then(([emailUser, phoneUser]) => {
  if (emailUser) {
    errors.email = "Email already exists";
    return res.status(400).json(errors);
  }

  if (phoneUser) {
    errors.phoneNo = "Phone no already exists";
    return res.status(400).json(errors);
  }
})


/* with async/await */

const [emailUser, phoneUser] await Promise.all([
  User.findOne({ email: req.body.email }).exec(),
  User.findOne({ phoneNo: req.body.phoneNo }).exec()
])
if (emailUser) {
  errors.email = "Email already exists";
  return res.status(400).json(errors);
}

if (phoneUser) {
  errors.phoneNo = "Phone no already exists";
  return res.status(400).json(errors);
}
thammada.ts
  • 5,065
  • 2
  • 22
  • 33