given the async nature of mongoose (or sequelize, or redis) queries, what do you do when you have multiple queries you need to make before rendering the view?
For in
router.get("/",function(req,res){
var locals = {};
var userId = req.params.userId;
async.parallel([
//Load user Data
function(callback) {
mongoOp.User.find({},function(err,user){
if (err) return callback(err);
locals.user = user;
callback();
});
},
//Load posts Data
function(callback) {
mongoOp.Post.find({},function(err,posts){
if (err) return callback(err);
locals.posts = posts;
callback();
});
}
], function(err) { //This function gets called after the two tasks have called their "task callbacks"
if (err) return next(err); //If an error occurred, we let express handle it by calling the `next` function
//Here `locals` will be an object with `user` and `posts` keys
//Example: `locals = {user: ..., posts: [...]}`
res.render('index.ejs', {userdata: locals.user,postdata: locals.posts})
});
Yep, this is a particularly annoying case in async code. What you can do is to put the code you'd have to duplicate into a local function to keep it DRY:
exports.index = function (req, res) {
var current_user = null
Player.find({last_logged_in : today()}).exec(function(err, players) {
if (err) return res.render('500');
function render() {
res.render('game/index', { title: 'Battle!',
players: players,
game_is_full: (players.length >= 6),
current_user: current_user
});
}
if (req.session.user_id) {
Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
if (err) return;
if (player) {
current_user = player
}
render();
})
} else {
render();
}
});
};
However, looking at what you're doing here, you'll probably need to look up the current player information in multiple request handlers, so in that case you're better off using middleware.
Something like:
exports.loadUser = function (req, res, next) {
if (req.session.user_id) {
Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
if (err) return;
if (player) {
req.player = player
}
next();
})
} else {
next();
}
}
Then you'd configure your routes to call loadUser
wherever you need req.player
populated and the route handler can just pull the player details right from there.
Nowadays you can use app.param in ExpressJS to easily establish middleware that loads needed data based on the name of parameters in the request URL.
http://expressjs.com/4x/api.html#app.param