As of version 6.0, you can use SCAN 0 TYPE set
. See https://redis.io/commands/scan#the-type-option
For versions prior to 6.0, you can use a Lua script to filter server-side, saving Round Trip Time (RTT) of doing TYPE
calls back from the client.
EVAL "local result = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2]) local filtered = {} for _,key in ipairs(result[2]) do if redis.call('TYPE', key).ok == ARGV[3] then table.insert(filtered, key) end end result[2] = filtered return result" 0 0 * set
The parameters to the script are 0(numkeys) cursor matchPattern type
. E.g. 0 0 * set
Here a friendly view of the Lua script:
local result = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2])
local filtered = {}
for _,key in ipairs(result[2]) do
if redis.call('TYPE', key).ok == ARGV[3] then
table.insert(filtered, key)
end
end
result[2] = filtered
return result
The returned value is the same as with SCAN
, just with the list of keys filtered by type.
As with SCAN
, you need to call multiple times until the cursor returned is zero.
This approach is much better than using KEYS
, as it won't block the server for a long time.
Next is the same script but with COUNT option, to do less or more work per call. The count should be greater than zero.
EVAL "local result = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2], 'COUNT', ARGV[3]) local filtered = {} for _,key in ipairs(result[2]) do if redis.call('TYPE', key).ok == ARGV[4] then table.insert(filtered, key) end end result[2] = filtered return result" 0 0 * 100 set
The parameters to the script are 0(numkeys) cursor matchPattern count type
. E.g. 0 0 * 100 set