在NODE中使用Redis SCAN

ldfqzlk8  于 2023-06-21  发布在  Redis
关注(0)|答案(7)|浏览(183)

我有一个Redis,里面有很多某种格式的键,我想得到匹配某种模式的键,并对它们进行一些操作。我不使用键的方法,因为它不建议在生产。使用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');
})();

有没有更好的方法来做到这一点,我错过了?

oxcyiej7

oxcyiej71#

我意识到这是一个非常古老的问题,但我发现所有其他的答案都很不令人满意。这里是另一个尝试,使用async await以相对干净的方式进行扫描(不使用另一个外部依赖项)。你可以很容易地修改它来连续地删除每一组找到的键(你可能想像这样批量处理它们,以防有很多键)。将它们放入数组只是演示了在此阶段可以对它们执行的一个非常基本的操作。

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

cgvd09ve2#

您可以使用递归来不断调用scan,直到完成为止。

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

bkkx9g8r3#

你可以尝试这个代码片段,每次迭代scan(1000)个键,然后'delete'。

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

brqmpdu14#

node-redis模块的一个不错的选择是使用扫描迭代器。示例:

const redis = require("redis");
const client = redis.createClient();

async function getKeys(pattern="*", count=10) {
    const results = [];
    const iteratorParams = {
        MATCH: pattern,
        COUNT: count
    }
    for await (const key of client.scanIterator(iteratorParams)) {
        results.push(key);
    }
    return results;
}

(Of当然,你也可以在for await循环中动态处理你的键,而不把它们存储在额外的数组中,如果这对你来说足够的话)。
如果你不想覆盖扫描参数(MATCH/COUNT),你可以跳过它们,不带参数执行client.scanIterator()(默认值将被使用,MATCH="*",COUNT=10)。

ui7jx7zq

ui7jx7zq5#

我认为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)
}

这是最后一点,显然是你应该关心的事情。你不需要自己小心地控制迭代器,你所需要做的就是使用一个用于理解。
我写了更多关于here

vsmadaxz

vsmadaxz6#

节点Redis文档

for await (const key of redisclient.scanIterator()) {
  // use the key!
  const k = await redisclient.get(key);
  console.log(k);
}

这是2023年最简单的方法。取决于你正在使用哪种承诺依赖性,一些其他答案可以在冻结时产生。for node js app using express this optimal check documents on link.所以如果你在2023年阅读这篇文章,这就是我的答案。

niknxzdl

niknxzdl7#

通过这个,它可能会有所帮助。
https://github.com/fritzy/node-redisscan
不要直接使用这个库,请浏览https://github.com/fritzy/node-redisscan/blob/master/index.js上的代码

相关问题