0

I'm having this issue where I want to get all of the keys in my redis' cache, store them in an array and send that array with express to the user. The problem is that I receive an empty array in the response with no objects in it. I have tried using for (const x of ...) {...} but that didn't work either. Tried searching up for answers on the internet , still nothing. Can you explain why is this happening and also here's my code.

exports.fetch = (_req, res) => {
  redis.keys("*", (err, reply) => {
    if (err) return res.json({ error: err });
    else {
      const rooms = [];
      reply.map((key) => {
        redis.get(key, (err, room) => {
          if (err) console.error(err);
          else rooms.push(room);
        });
      });

      return res.json(rooms);
    }
  });
};

Update

Thanks everyone for responding.

As @boolfalse suggested, I used async module and it worked!

Here's my updated code

exports.fetch = (_req, res) => {
  redis.keys("*", (err, reply) => {
    if (err) return res.json({ error: err });
    else {
      async.map(
        reply,
        (key, cb) => {
          redis.get(key, (err, room) => {
            if (err) return cb(err);
            else return cb(null, room);
          });
        },
        (err, results) => {
          if (err) return res.json({ error: err });
          else return res.json(results);
        }
      );
    }
  });
};

But I kinda don't understand why and how it worked...

Thanks anyways for doing research and providing your time

1 Answers1

0

Thanks to user @boolfalse for helping me out.

Here's the solution URL to this issue.

First of all, the issue in your question is that, inside the for loop, client.get is invoked with an asynchronous callback where the synchronous for loop will not wait for the asynchronous callback and hence the next line res.json({data:jobs}); is getting called immediately after the for loop before the asynchronous callbacks. At the time of the line res.json({data:jobs}); is getting invoked, the array jobs is still empty [] and getting returned with the response.

To mitigate this, you should use any promise modules like async, bluebird, ES6 Promise etc.

Modified code using async module,

    app.get('/jobs', function (req, res) {
        var jobs = [];
        client.keys('*', function (err, keys) {
            if (err) return console.log(err);
            if(keys){
                async.map(keys, function(key, cb) {
                   client.get(key, function (error, value) {
                        if (error) return cb(error);
                        var job = {};
                        job['jobId']=key;
                        job['data']=value;
                        cb(null, job);
                    }); 
                }, function (error, results) {
                   if (error) return console.log(error);
                   console.log(results);
                   res.json({data:results});
                });
            }
        });
    });

But from the Redis documentation, it is observed that usage of Keys are intended for debugging and special operations, such as changing your keyspace layout and not advisable to production environments.

Hence, I would suggest using another module called redisscan as below which uses SCAN instead of KEYS as suggested in the Redis documentation.

Something like,

    var redisScan = require('redisscan');
    var redis     = require('redis').createClient();
           
    
    redisScan({
            redis: redis,
            each_callback: function (type, key, subkey, value, cb) {
                console.log(type, key, subkey, value);
                cb();
            },
            done_callback: function (err) {
                console.log("-=-=-=-=-=--=-=-=-");
                redis.quit();
            }
        });