Reputation: 1381
I am relatively new to using Promises and MongoDB / Mongoose, and am trying to chain a flow through several database queries into an efficient and reliable function.
I want to know if my final function is a good and reliable way of achieving what I want, or if there are any issues or any improvements that can be made.
The process is as follows:
1) Check whether or not the user already exists
usersSchema.findOne({
email: email
}).then(res => {
if(res==null){
// user does not exist
}
}).catch(err => {});
2) Add the new user to the database
var new_user = new usersSchema({ email: email });
new_user.save().then(res => {
// new user id is res._id
}).catch(err => {});
3) Assign a free promotional code to the user
codeSchema.findOneAndUpdate({
used: false,
user_id: true
},{
used: true,
user_id: mongoose.Types.ObjectId(res._id)
}).then(res => {
// user's code is res.code
}).catch(err => {});
Obviously, each query needs to execute in sequence, so after a lot of research and experimentation into how to do this I have combined the queries into the following function, which seems to be working fine so far:
function signup(email){
// check email isn't already signed up
return usersSchema.findOne({
email: email
}).then(res => {
if(res==null){
// add to schema
var new_user = new usersSchema({ email: email });
// insert new user
return new_user.save().then(res => {
var result = parse_result(res);
// assign a code
return codesSchema.findOneAndUpdate({
used: false,
user_id: true
},{
used: true,
user_id: mongoose.Types.ObjectId(result._id),
});
});
}else{
return 'The user already exists';
}
});
}
signup('[email protected]').then(res => {
console.log('success, your code is '+res.code);
}).catch(err => {
console.log(err);
});
I'm still trying to get my head around exactly how and why this works - the function is returning a promise, and each nested promise is returning a promise.
My main concerns are that there is a lot of nesting going on (is there perhaps a way to do this by chaining .then() callbacks instead of nesting everything?) and that the nested promises don't appear to have error catching, although as the signup() function itself is a promise this seems to catch all the errors.
Is anyone knowledgeable on the subject able to confirm whether my process looks good and reliable or not? Thanks!
Upvotes: 2
Views: 2698
Reputation: 5265
To avoid indentation-hell, if you return a value from the function passed to a Promise's .then()
-method, you can chain multiple .then()
as a neat and tidy pipeline. Note that you can also return a Promise that has pending status, and then next function in line will execute when it has resolved.
function signup (email) {
return usersSchema.findOne({
email: email
}).then(res => {
if (res) throw 'The user already exists'
var new_user = new usersSchema({ email: email })
return new_user.save()
}).then(res => {
var result = parse_result(res)
return codesSchema.findOneAndUpdate({
used: false,
user_id: true
},{
used: true,
user_id: mongoose.Types.ObjectId(result._id)
})
})
}
Even better, if you have the possibility to use async/await
(Node v7.6 or above), your code can look like normal blocking code:
async function signup (email) {
let user = await usersSchema.findOne({ email: email })
if (user) throw 'The user already exists'
let new_user = await new usersSchema({ email: email }).save()
let result = parse_result(new_user)
return codesSchema.findOneAndUpdate({
used: false,
user_id: true
},{
used: true,
user_id: mongoose.Types.ObjectId(result._id)
})
}
Your original function call code works on both without changes.
Upvotes: 4
Reputation: 2487
you code can be improve in this way
function signup(email){
// check email isn't already signed up
return usersSchema.findOne({
email: email
}).then(res => {
if(res==null){ // add to schema
var new_user = new usersSchema({ email: email });
// insert new user
return new_user.save()
}else{
return Promise.reject(new Error('The user already exists'));
}
})
.then(res => {
var result = parse_result(res);
// assign a code
return codesSchema.findOneAndUpdate({used: false,user_id: true},{used: true,user_id: mongoose.Types.ObjectId(result._id),});
});
}
signup('[email protected]').then(res => {
console.log('success, your code is '+res.code);
}).catch(err => {
console.log(err);
});
Upvotes: 2