Happydevdays Happydevdays - 3 months ago 17
Node.js Question

node.js - how to pass additional parameters to async.map

Background Information

I'm trying to write some javascript / node.js code that will do the following:

  1. Query a redis database and get back a bunch of keys from my hash. This is what the command looks like on the redis-cli:> hkeys widgets:1231231234
    1) "13:00:00_17:00:00_mtwrf"
    2) "00:00:00_00:00:00"
    3) "08:00:00_12:00:00_mtwrf"

or> hkeys widgets:2222222222
1) "00:00:00_00:00:00"

Each widget will have at least one key... called the default key. Default keys look like this: "00:00:00_00:00:00"

For each HKEYS query, if there's more than one result returned, I need to test each key returned (except the default) against a set of match criteria. Whichever key matches, is what is used to do a subsequent HGET against redis. So for example, in the first result set shown above... If key 3 was a match I would run the following command:> hget widgets:2222222222 08:00:00_12:00:00_mtwrf
"some value">

If neither key 1 or 3 matches, then I query for the default key.


I've recently discovered the async module. I'm currently using it in my code to loop through the results from HKEYS.
Please see the code below:

async.map Code

router.get('/:widgetnum', function(req, res, next) {
//validate widgetnum format
var widgetnum = req.params.widgetnum;
if ( !valid_widget(widgetnum) ) {
var retval = {"res":false, "msg":"malformed widgetnum"};
} else {
var keys = {};
redis.hkeys("widgets:" + widgetnum, function(err, data){
if (err) {
if (data) {
current = getCurrentUTC(); // needed by iterator for match criteria. Using a global variable for now.
async.map(data, hash_iterator, function (err, iterator_results) {
if (iterator_results) {
console.log("it are: " + iterator_results);
}); //end async map

}); //end redis.hkeys

Question / Problem

This is working in the sense that for each key returned by HKEYS, I'm able to run the "hash_iterator" function.

However, once inside the iterator function, after evaluation / running my match criteria on each result, I don't have all the information I need to run the secondary HGET query.

The code:

async.map(data, hash_iterator, function (err, iterator_results)

passes just the values:


But I need the hash name (in this case "widgets:" ) and the widgetnum to make the HGET call.

I guess I can use global variables... but I wanted to make sure that my approach in general is correct here.

Any input would be appreciated.

Here's the hash_iterator logic:

var hash_iterator = function (redis_key, doneCallBack) {
var results = {};
console.log("processing..." + redis_key);
//skip if default rule....
if (redis_key.indexOf('00:00:00_00:00:00') == -1){
//need to write logic here to do HGET and save
//results somewhere... in case no other keys match

} else {
// run some logic to test match criteria.
if (matchfound) {
console.log("bingo. found match in " + redis_key);
redis.hget(hashname + widgetnum + redis_key, function (e, results){
if (results) {
return doneCallBack(null, results);
} else {
return doneCallBack(null, null);


}else {
console.log ("no match");
return results;


You can solve it in functional style with map. Just generate array of pairs and then pass it to async.map, for example from [1,2,3] you can generate [['key', '1'], ['key', '2'], ['key', 3]]

So here the code, that generating pairs:

var pairs = data.map(function(ts) {
  return [`widgets:${widgetnum}`, ts];

Inside async.map iterator callback you can access key with iterator_results[0]

But in your case the variable widgetnums is not global variable. It's just variable from upper scope and you can use it inside nested functions if you define it in propper scope. It's very useful trick that called lexical closure.