In Redis, keys user*
will print all keys starting with user
. For example:
keys user* 1) "user2" 2) "user1"
Now, I want all keys that don't start with user
to be printed. How could I do that?
Redis does not offer a way to bulk delete keys. You can however use redis-cli and a little bit of command line magic to bulk delete keys without blocking redis. This command will delete all keys matching users:* If you are in redis 4.0 or above, you can use the unlink command instead to delete keys in the background.
To list the keys in the Redis data store, use the KEYS command followed by a specific pattern. Redis will search the keys for all the keys matching the specified pattern. In our example, we can use an asterisk (*) to match all the keys in the data store to get all the keys.
You can use the DUMP and RESTORE commands to duplicate the key: use the DUMP command to serialize the value of a key. use the RESTORE command to restore the serialized value to another key.
The Redis KEYS command returns all the keys in the database that match a pattern (or all the keys in the key space). Similar commands for fetching all the fields stored in a hash is HGETALL and for all fetching the members of a SMEMBERS. The keys in Redis themselves are stored in a dictionary (aka a hash table).
IMPORTANT: always use SCAN
instead of (the evil) KEYS
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:
stringmatchlen
to match your requirements, possibly submitting it as a PR.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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With