Skip to content

Instantly share code, notes, and snippets.

@itamarhaber
Last active May 21, 2019 13:24
Show Gist options
  • Save itamarhaber/19c8393f465b62c9cfa8 to your computer and use it in GitHub Desktop.
Save itamarhaber/19c8393f465b62c9cfa8 to your computer and use it in GitHub Desktop.
Regex-like key name pattern matching in Redis
foo@bar:~$ redis-cli
127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> set user:1 1
OK
127.0.0.1:6379> set use:the:force luke
OK
127.0.0.1:6379> set non:user a
OK
foo@bar:~$ redis-cli --eval scanregex.lua , "^user"
1) "user:1"
foo@bar:~$ redis-cli --eval scanregex.lua , "^user" 1
1) "use:the:force"
2) "non:user"
--[[
Use SCAN to search the entire keyspace and filter keys
with Lua patterns which are not POSIX regex, but ATM
(v3) the best thing available in Redis.
KEYS: none
ARGV: 1: Lua pattern (defaults to .* if unprovided)
2: Complement switch (i.e. not)
]]--
local re = ARGV[1]
local nt = ARGV[2]
local cur = 0
local rep = {}
local tmp
if not re then
re = ".*"
end
repeat
tmp = redis.call("SCAN", cur, "MATCH", "*")
cur = tonumber(tmp[1])
if tmp[2] then
for k, v in pairs(tmp[2]) do
local fi = v:find(re)
if (fi and not nt) or (not fi and nt) then
rep[#rep+1] = v
end
end
end
until cur == 0
return rep
@zapman449
Copy link

Beware... this will block all other redis calls while this lua script executes (a full DB scan). See http://redis.io/commands/eval for the section "Atomicity of scripts" to see why.

Clever use, but not a good idea for production.

@itamarhaber
Copy link
Author

Oh - definitely don't use this in production :)

@FeatureCreep
Copy link

FeatureCreep commented Oct 18, 2017

If your script takes SCAN-like arguments cursor and count, then you could avoid a complete DB walk on any one invocation. Keep SCAN-like semantics, so you would need to return the cursor after every iteration, to allow the caller to resume.

@itamarhaber
Copy link
Author

@FeatureCreep - totally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment