I am trying to move database calls out of my controller to clean things up and make them testable. When they are in the controller, everything moves smoothly. I moved them out of the controller and added an async to ensure that we wait. Otherwise, I would call the res.render()
function within the .exec()
of Users.findOne()
. Now, once I am using async/await, the function in my controller thinks that there is no user because it is not waiting.
There are several questions on SO regarding async await, but I did not find one that resolves my issue. I did verify that my User is returned, and I added console logs to show the path.
- node mongoose async await seemed promising, but their actual problem was failure to return the item, and mine returns fine
- async not waiting for await is an issue with kotlin
- async await not waiting Seems very applicable, but I do not understand fully the answer about nested await/async - the problem the asker had was more complicated than my query because they are dealing with loops and forEach
- Javascript async await is spot on, so I checked that the mongoose function returns a promise. Mongoose docs show that it is ready for async because calls return a promise.
Assume we are resolving the route /users
routes/index.js
// requires & other routes not shown
router.get('/users', controller.testUserShow);
controllers/index.js
// requires & other routes not shown
exports.testUserShow = async (req, res, next) => {
if (req.user) { // if code to get user is right here, with no async/await, the user is found and the code continues
try {
found = await services.fetchUser(req.user._id)
console.log("I am not waiting for at testusershow")
console.log(found); //undefined
// go on to do something with found
} catch(e) {
throw new Error(e.message)
}
}
}
services/index.js
const db = require('../db')
exports.fetchUser = async (id) => {
try {
console.log("fetchUser is asking for user")
return await db.returnUser(id)
} catch(e) {
throw new Error(e.message)
}
}
db/index.js
const User = require('../models/user');
exports.returnUser = async (id) => {
User.findById(id)
.exec(function(err, foundUser) {
if (err || !foundUser) {
return err;
} else {
// if this was in the controller
// we could res.render() right here
console.log("returnUser has a user");
console.log(foundUser); // this is a User
return foundUser;
}
});
}
The console log goes
fetchUser is asking for user
I am not waiting for at testusershow
undefined
returnUser has a user
// not printed... valid user
I would expect the initial call to be undefined if I was calling something that did not return a promise, but User.findOne()
should.
What am I missing here?