Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Redis SCAN in NODE

I have Redis with a lot of keys in some format and I want to get keys that match some pattern and do some operations on them. I don't use KEYS method since it's not recommend in production. Using SCAN I'm wondering what is the best way to write it in code. I have to do something like a while loop but using promises, my current solution looks like this (code is simplified a little):

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

Is there a better way to do it that I'm missing?

like image 474
Madbrush Avatar asked Jun 05 '16 14:06

Madbrush


People also ask

How do I scan using Redis?

SCAN basic usage SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. In the example above, the first call uses zero as a cursor, to start the iteration.

How do I use Redis in node JS?

Create new session. js file in the root directory with the following content: const express = require('express'); const session = require('express-session'); const redis = require('redis'); const client = redis. createClient(); const redisStore = require('connect-redis')(session); const app = express(); app.

Is Redis scan blocked?

So yes, SCAN is blocking, but it's usually not a big deal, and is only blocking when Redis is actually processing the command. Omit the COUNT and MATCH arguments, and it's probably not an issue. Whether it becomes an issue after adding MATCH and/or COUNT arguments will depend on your data and your use of SCAN.

Why Redis is used in Node JS?

Redis, an in-memory database that stores data in the server memory, is a popular tool to cache data. You can connect to Redis in Node. js using the node-redis module, which gives you methods to retrieve and store data in Redis.


2 Answers

Nice option for node-redis module is to use scan iterators. Example:

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 course you can also process your keys on the fly in for await loop without storing them in additional array if that's enough for you).

If you do not want to override scan parameters (MATCH/COUNT) you can just skip them and execute client.scanIterator() without parameter (defaults will be used then, MATCH="*", COUNT=10).

like image 151
Zuku Avatar answered Sep 20 '22 19:09

Zuku


I realize this is a really old question, but I found all of the other answers very unsatisfying. Here is yet another attempt to scan in a relatively clean way using async await (WITHOUT the use of yet another external dependency). You can easily modify this to continuously delete each set of found keys (you would want to tackle them in batches like this in case there are LOTS). Pushing them into an array just demonstrates one very basic thing you could do with them during this stage.

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;
}
like image 38
J.Wolfe Avatar answered Sep 18 '22 19:09

J.Wolfe