how to get keys which does not match a particular pattern in redis?

IMPORTANT: always use SCAN instead of (the evil) KEYS
do not use <code>KEYS</code>

Redis' pattern matching is somewhat functionally limited (see the implementation of stringmatchlen in util.c) and does not provide that which you seek ATM. That said, consider the following possible routes:

  1. Extend stringmatchlen to match your requirements, possibly submitting it as a PR.
  2. Consider what you're trying to do - fetching a subset of keys is always going to be inefficient unless you index them, consider tracking the names of all non-user keys (i.e.g. in a Redis Set) instead.
  3. If you are really insistent on scanning the entire keyspace and match against negative patterns, one way to accomplish that is with a little bit of Lua magic.

Consider the following dataset and script:

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

Lua (save this as scanregex.lua):

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

Output - first time regular matching, 2nd time the complement:

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"

@Karthikeyan Gopall you nailed it in your comment above and this saved me a bunch of time. Thanks!

Here's how you can use it in various combinations to get what you want:

redis.domain.com:6379[1]> set "hello" "foo"
OK
redis.domain.com:6379[1]> set "hillo" "bar"
OK
redis.domain.com:6379[1]> set "user" "baz"
OK
redis.domain.com:6379[1]> set "zillo" "bash"
OK
redis.domain.com:6379[1]> scan 0
1) "0"
2) 1) "zillo"
   2) "hello"
   3) "user"
   4) "hillo"
redis.domain.com:6379[1]> scan 0 match "[^u]*"
1) "0"
2) 1) "zillo"
   2) "hello"
   3) "hillo"
redis.domain.com:6379[1]> scan 0 match "[^u^z]*"
1) "0"
2) 1) "hello"
   2) "hillo"
redis.domain.com:6379[1]> scan 0 match "h[^i]*"
1) "0"
2) 1) "hello"

Tags:

Redis