如何在JavaScript中获取Redis中的所有键和值?

24

我正在使用JavaScript创建一个节点API。我已经将Redis用作我的键值存储。我在应用程序中创建了一个Redis客户端,并能够获取特定键的值。

我想检索所有键以及它们的值。到目前为止,我已经完成了以下工作:

app.get('/jobs', function (req, res) {
    var jobs = [];
    client.keys('*', function (err, keys) {
        if (err) return console.log(err);
        if(keys){
            for(var i=0;i<keys.length;i++){
                client.get(keys[i], function (error, value) {
                    if (err) return console.log(err);
                    var job = {};
                    job['jobId']=keys[i];
                    job['data']=value;
                    jobs.push(job);
                });  
            }
            console.log(jobs);
            res.json({data:jobs});
        }
    });
});

但是我总是在响应中得到空数组。

有没有办法在JavaScript中实现这个?

谢谢


拜托,@Bhushan——你有3K分了,应该知道提问时要附上代码... - MoshMage
可能是Redis命令获取所有可用键?的重复问题。 - MoshMage
@MoshMage 我添加了代码。抱歉,我有点忙。 - Bhushan Gadekar
https://dev59.com/sFoU5IYBdhLWcg3wQ1Z3#38247686 - anothermh
@BhushanGadekar 你可以在下面检查我的答案。 - Aruna
这个问题是关于从异步函数返回值的,因此它是重复的 https://dev59.com/RGYq5IYBdhLWcg3wwDRA - ponury-kostek
5个回答

26
首先,你问题中的难点在于,在for循环内部,使用异步回调调用了client.get。由于同步的for循环不会等待异步回调,因此在异步回调之前就立即调用了res.json({data:jobs});。在调用res.json({data:jobs});时,数组jobs仍然为空[],因此返回的响应也是空的。

要解决这个问题,你需要使用任何一个Promise模块,例如asyncbluebirdES6 Promise等。

使用async模块修改后的代码:

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});
            });
        }
    });
});

然而从 Redis文档中可以看出,Keys 命令旨在用于调试和特殊操作,比如更改键空间布局,并不建议在生产环境中使用。

因此,我建议使用另一个名为 redisscan 的模块,它使用 SCAN 而不是 KEYS,正如在 Redis文档中所建议的。

就像这样:

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();
        }
    });

9

两个请求的组合:

import * as ioredis from 'ioredis';

const redis = new ioredis({
    port: redisPort,
    host: redisServer,
    password: '',
    db: 0
  });

const keys = await redis.collection.keys('*');
const values = await redis.collection.mget(keys);

这两个数组的顺序将保持相同。


这个不起作用。没有keys属性。 - rakesht
我真正想知道的是如何限制键。 - nanquim
@rakesht - 看起来已经在这里了 https://github.com/luin/ioredis/issues/828#issuecomment-476716136 - Iurii Perevertailo
如果你想限制,那么使用扫描方法来获取键,它快速、可靠且非阻塞。 - Adnan

4

4
这将获取所有键,但没有值:
const redis = require('redis');
const client = redis.createClient();

client.keys('*', (err, keys) => {
  // ...
});

现在,您需要以通常的方式获取这些键的值。例如:

Promise.all(keys.map(key => client.getAsync(key))).then(values => {
  // ...
});

或者使用 async 模块或任何其他方式。

1
值得一提的是,文档明确指出该命令不应用于此目的。 - baao
1
@baao 是的。我认为获取所有键和所有值是一种需要,表明 Redis 在这里使用方式很奇怪。不幸的是,问题是关于解决方案而不是问题,所以很难推荐其他任何东西。 - rsp
这里确实使用了一种奇怪的方式来使用Redis。 :D - baao
1
尽管有这个问题,更好的解决方案是使用SCAN而不是KEYS - Itamar Haber

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接