I'm still trying to get into node.js and probably getting some things not quite right. What I'm looking foward to accomplish is to query first a hmap containing a list of rooms. This list is going to be iterated trough to get for each room further details like room name etc.
Here's what the query should return:
redis 127.0.0.1:6379> lrange rooms 0 -1
1) "room:5000"
and
redis 127.0.0.1:6379> hgetall room:5000
1) "name"
2) "room1"
3) "admin"
4) "user:1001"
5) "public"
6) "true"
here's my function within the routes.index
exports.index = function(req, res){
var render_rooms = new Array();
req.app.settings.redis.lrange('rooms',0,-1, function(error, rooms) {
if (error) {
console.log('Error: '+ error);
}
else {
rooms.forEach(function(room){
console.log("room: " + room);
req.app.settings.redis.hgetall(room, function(error, roomdetails){
if (error) {
console.log('Error: '+ error);
}
else {
console.log("roomdetails: " + roomdetails.public);
if(roomdetails.public == "true"){
render_rooms.push(roomdetails.name);
}
}
});
});
// console.log('Name: ' + result);
// res.render('account', { title: 'account title', user: req.user.username, votes: result });
}
});
console.log("length: " + render_rooms.length);
res.render('index', { title: 'Index', username: req.user.username, rooms: render_rooms });
};
I'm not sure if I'm using node_redis properly to achieve this. Further I came up with the idea to store all room details in an array which I'm looking forward to send to the view. Apparently the list always display no elements as I guess is called before the list is filled as I'm missing some essential callback functionality. Howeever I'm not able to fiddle it in. Can someone explain me in some more detail how it "should" work?
Your basic problem is that you need to wait to render the render_rooms
array until all the asynchronous processing has completed. The way it is written now, res.render
is being called before any of the async Redis queries have completed.
Something like this:
exports.index = function(req, res){
var render_rooms = new Array();
req.app.settings.redis.lrange('rooms',0,-1, function(error, rooms) {
// Keep track of the number of rooms we have left to process.
var roomcount = rooms.length;
if (error) {
console.log('Error: '+ error);
}
else {
rooms.forEach(function(room){
console.log("room: " + room);
req.app.settings.redis.hgetall(room, function(error, roomdetails){
if (error) {
console.log('Error: '+ error);
}
else {
console.log("roomdetails: " + roomdetails.public);
if(roomdetails.public == "true"){
render_rooms.push(roomdetails.name);
}
// Render code moves to here and is only run after all rooms
// have been processed.
if (--roomcount === 0) {
console.log("length: " + render_rooms.length);
res.render('index', {
title: 'Index',
username: req.user.username,
rooms: render_rooms
});
}
}
});
});
}
});
};
Once you get comfortable with what this is doing, take a look at cleaning it up a bit by using async.forEach
or async.forEachSeries
which more cleanly support this type of flow.