Reputation: 27811
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' (i.e. 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?
Upvotes: 0
Views: 6062
Reputation: 27811
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 } ]
Upvotes: 2
Reputation: 5981
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.
Upvotes: 3