How to get keys that do not match a specific pattern in redis?

In Redis, keys user* will print all keys starting with user . For instance:

 keys user* 1) "user2" 2) "user1" 

Now I want all the keys that did not start with user to be typed. How can i do this?

+6
source share
3 answers

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

Matching Redis patterns is somewhat functionally limited (see the stringmatchlen implementation in util.c ) and does not provide what you look for an ATM. We consider the following possible routes:

  • Extend stringmatchlen to fit your requirements, possibly sending it as a PR.
  • Think about what you are trying to do - selecting a subset of keys will always be ineffective, if you do not index them, try instead to keep track of the names of all non-user keys (i.e., in the Redis set).
  • If you really insist on scanning the entire key space and matching against negative patterns, one way to achieve this is with Lua's little 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 

Exit - the first regular match, the second time - addition:

 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" 
+11
source

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

Here 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" 
+4
source

According to redis, the key documentation of the command supports glob style patterns, not regular expressions .

and if you look at the documentation, you will see that "!" a character is not special as opposed to regular expressions.

Here is a simple test that I ran in my own db:

 redis 127.0.0.1:6379> set a 0 OK redis 127.0.0.1:6379> set b 1 OK redis 127.0.0.1:6379> keys * 1) "a" 2) "b" redis 127.0.0.1:6379> keys !a (empty list or set) // I expected "b" here redis 127.0.0.1:6379> keys !b (empty list or set) // I expected "a" here redis 127.0.0.1:6379> keys [!b] 1) "b" redis 127.0.0.1:6379> keys [b] 1) "b" redis 127.0.0.1:6379> keys [ab] 1) "a" 2) "b" redis 127.0.0.1:6379> keys ![b] (empty list or set) 

Therefore, I just don’t think that what you are trying to achieve is possible with the keys command.

In addition, the key command is not very suitable for the working environment, since it locks your entire redis database.

I would recommend getting all the keys using the scan command, saving them locally and deleting them using LUA

+2
source

Source: https://habr.com/ru/post/986219/


All Articles