I have an app which is structured: index > routes > endpoints > core, where endpoints process requests to send a response and core accesses the database. The point of dividing controllers in to these two components was partially to make things work after a DB change and partially to simplify my code. The issue is that I can only get the results of a mongoose query function in my module via callback, which does not simplify my code at all.
What I want:
var user = coreModule.findUser({id:123}) //return user
var posts = coreModule.findPosts({author:123}) //return posts array
res.render("home", {user:user, posts:posts})
By doing:
//core module example
findUser: function(params){
User.findOne(params, function(err,docs){
if(err){
return err
}else{
return docs
}
}
}
But instead I have to use a mess of callback functions which defeat half of the purpose of core modules in the first place. I have seen that you can do this with SQL and Knex, but it will not work with mongoose. If what I am trying to do is impossible, is there a mongoose substitute that would be recommended in this case?
Use the Async/Await Syntax:
const findUser = async function (params) {
try { return await User.findOne(params)
} catch(err) { console.log(err) }
}
const userSteve = findUser({firstName: Steve})
Each time you need to use the information from a Query, use the await
prefix within an async
function. This will allow you to use asynchronous nature of a Mongoose query within synchronous code that needs that query result to continue.
For your code:
coreModule.findUser = async function (userId) {
return await User.findOne({id:_userId})
}
coreModule.findPosts = async function(authorId) {
return await Posts.find({postedBy: authorId})
}
const foundUser = coreModule.findUser(123);
const foundPosts = coreModule.findPosts(123);
res.send({user: foundUser, posts: foundPosts})
If you would like both queries to fire off simultaneously, you can use Promise.all()
coreModule.findUser = function (userId) {
return User.findOne({id:_userId})
}
coreModule.findPosts = function(authorId) {
return Posts.find({postedBy: authorId})
}
const [foundUser, foundPosts] =
await Promise.all(
[coreModule.findUser(123), coreModule.findPosts(123)]
);
res.send({user: foundUser, posts: foundPosts})
If you have both Queries located at separate EndPoints in your API, you could also construct two fetch requests aimed at both endpoints and fire those off simultaneously on the Client-Side with Promise.all()
I hope this helped!
Edit: I have edited my post with this working example which I have tested in my API:
module.exports.test = async function(req, res, next) {
const module1 = function(params) {
return ShoppingCartModel.find({_id: params})
}
const module2 = function(params) {
return User.find({_id: params})
}
const array = [module1('5a739dbc45424d2904faca5b'), module2('5a739dbc45524d2904faca5b')]
const promise = await Promise.all(array)
res.json(promise)
}
Some examples of incorrect returns:
Incorrect:
const array = [ShoppingCartModel.find({}), ShoppingCartModel.find({})]
// console.log(array) = Mongoose Query Constructors
const promise = Promise.all(array)
// console.log(promise) = Promise { <pending> }
Correct:
const array = [ShoppingCartModel.find({}), ShoppingCartModel.find({})]
const promise = await Promise.all(array)
Incorrect:
// Return full fledged promise from Mongoose query using .exec()
const array = [ShoppingCartModel.find({}).exec(), ShoppingCartModel.find({}).exec()]
// console.log(array) = [ Promise { <pending> }, Promise { <pending> } ]
const promise = Promise.all(array)
// console.log(promise) = Promise { <pending> }
Correct:
const array = [ShoppingCartModel.find({}).exec(), ShoppingCartModel.find({}).exec()]
const promise = await Promise.all(array)
You must await the result of Promise.all
, or else your function will blow through the function calls, send an empty JSON object back to the front-end, and console.log pending promises which are not given time to resolve
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With