简体   繁体   中英

How to get the TTL of multiple Redis keys from Node

I'm trying to show a view of all keys that look like 'myprefix:*' and their TTL. I can then allow an admin to either expire a key, or 'touch it' (ie add an hour to the expiration).

I can use redisClient.keys('myprefix:*', (err, keys) => {}) to get my keys, but the redisClient.ttl command only accepts a single key, not an array. I don't want to iterate over the array and send n ttl commands.

I know I can probably use multi to send a transaction of ttl commands, but I'm wondering if there's a better way (in JavaScript - not shell ) to get all the keys and their TTL in one/two commands?

As Redis embedds a Lua interpreter , a solution would be to create a Redis Lua script like this one:

local keys = redis.call('keys','myprefix:*')
local result = {}
for i,k in ipairs(keys) do 
    local ttl = redis.call('ttl', k)
    result[i] = {ttl}
end
return result

Using ioredis, you can simplify the declaration of Redis Lua scripts in NodeJS:

var Redis = require('ioredis');
var redis = new Redis();

// This will define a command getTtls:
redis.defineCommand('getTtls', {
  numberOfKeys: 1,
  lua: "local keys = redis.call('keys', KEYS[1]..':*')\n local result = {}\n for i,k in ipairs(keys) do \n local ttl = redis.call('ttl', k)\n result[i] = {ttl}\n end\n return result"
});

// now invoke this new command, giving the prefix as a parameter
redis.getTtls('myprefix', function (err, result) {
    console.log(result);
});

The script is defined in your NodeJS application, but executed by Redis.

Don't forget that using the KEYS command in production is often a bad idea, as it scans the whole database in one operation and so makes your Redis instance unresponsive to other requests during a time which could be rather long (it depends on the number of keys in your database). If it's an issue in your use case, you'll probably want to use a SCAN command instead.

Finally resorted to using multi . I do understand both using keys and multi is highly not recommended in production. But the number of keys I'm handling right now is quite small (less than 10).

Using keys + multi to get the ttl of N keys results in 2 network trips, rather than N+1.

As it grows, I'll reevaluate the solution. I posted my code below if anyone ever needs it:

let getKeys = prefix => {
    return new Promise((resolve, reject) => {
      redisClient.keys(`${prefix}:*`), (err, keys) => {
        if(err) {
          reject(err)
        }
        else {
          let multi = redisClient.multi();
          keys.forEach(k => multi.ttl(k));
          multi.exec((err2, ttls) => {
            if(err2) {
              reject(err2);
            }
            else {
              let result = keys.map((k, i) => ({key: k.replace(`${prefix}:`, ''), ttl: ttls[i]}));
              resolve(result);
            }
          });
        }
      });
    });
  };

This yields an array:

[ { key: '05460a69f7c0d313b7edfcca4f267cee', ttl: 3034 },
  { key: 'b1065bfa82408a10e2d2d0a50df1eef9', ttl: 3031 },
  { key: 'c3aeced2ef08f1c728f0b367c50a962a', ttl: 3019 } ]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM