在NODE中使用Redis SCAN

时间:2016-06-05 14:00:03

标签: node.js redis ecmascript-6 bluebird

我的Redis中有许多格式的密钥,我希望获得与某些模式匹配的密钥并对它们进行一些操作。我没有使用KEYS方法,因为它不适合生产。使用SCAN我想知道在代码中编写它的最佳方法是什么。我必须做一些像while循环但使用promises的东西,我现在的解决方案看起来像这样(代码简化了一点):

'use strict'
const Promise = require('bluebird');
const config = require('./config');
const client = require('./clinet');

let iterator = 0;
Promise.coroutine(function* () {
  do {
    iterator = yield clinet.scanAsync(iterator, 'myQuery', 'COUNT', config.scanChunkSize)
      .then(data => {
        let nextIterator = data[0];
        let values = data[1];
        //do some magic with values
        return nextIterator;
      })
  } while (iterator !== '0');
})();

有没有更好的方法可以让我失踪?

5 个答案:

答案 0 :(得分:13)

您可以使用递归来保持调用扫描直到完成。

function scanAsync(cursor, pattern, returnSet){

    return redisClient.scanAsync(cursor, "MATCH", pattern, "COUNT", "100").then(
        function (reply) {

            cursor = reply[0];
            var keys = reply[1];
            keys.forEach(function(key,i){
                returnSet.add(key);
            });

            if( cursor === '0' ){
                return Array.from(returnSet);
            }else{
                return scanAsync(cursor, pattern, returnSet)
            }

    });
}

传入Set()以确保密钥不重复

myResults = new Set();

scanAsync('0', "NOC-*[^listen]*", myResults).map( 
    function( myResults ){ console.log( myResults); }
);

答案 1 :(得分:4)

您可以在每次迭代时尝试将此代码段移至scan(1000)个密钥并“删除”。

var cursor = '0';
function scan(pattern,callback){

  redisClient.scan(cursor, 'MATCH',pattern,'COUNT', '1000', function(err, reply){
    if(err){
        throw err;
    }
    cursor = reply[0];
    if(cursor === '0'){
        return callback();
    }else{

        var keys = reply[1];
        keys.forEach(function(key,i){                   
            redisClient.del(key, function(deleteErr, deleteSuccess){
                console.log(key);
            });
        });


        return scan(pattern,callback);
    }
  });
}

scan(strkey,function(){
    console.log('Scan Complete');
});

答案 2 :(得分:2)

我意识到这是一个非常老的问题,但是我发现所有其他答案都非常不令人满意。这是使用异步等待以相对干净的方式进行扫描的另一种尝试(不使用其他外部依赖项)。您可以轻松地对其进行修改,以连续删除每组找到的密钥(如果有很多东西,您可能希望像这样批量处理)。将它们推入数组只是演示了在此阶段可以使用它们做的一件非常基本的事情。

const redis = require('redis');
const { promisify } = require('util');

const client = redis.createClient({...opts});
const scan = promisify(client.scan).bind(client);

const scanAll = async (pattern) => {
  const found = [];
  let cursor = '0';

  do {
    const reply = await scan(cursor, 'MATCH', pattern);

    cursor = reply[0];
    found.push(...reply[1]);
  } while (cursor !== '0');

  return found;
}

答案 3 :(得分:0)

通过这个,它可能有所帮助。

https://github.com/fritzy/node-redisscan

不要使用该库,请查看可用的代码 https://github.com/fritzy/node-redisscan/blob/master/index.js

答案 4 :(得分:0)

我认为Redis的节点绑定在这里将太多的责任推给了调用者。因此,我也使用node中的生成器创建了自己的库进行扫描:

const redis = require('redis')
const client = redis.createClient(…)
const generators = require('redis-async-gen')
const { keysMatching } = generators.using(client)

…

for await (const key of keysMatching('test*')) {
  console.info(key)
}

这显然是您应该关心的最后一点。无需自己仔细控制迭代器,您所需要做的就是使用for理解。

我写了更多有关here的文章。