itaied
itaied

Reputation: 7107

Redis update with query

I'm new to redis, but from reading the docs I couldn't find if it is possible to update a value with a query (like mongo or postgres).

For example, I want to execute some logic for players in the lobby. I want to update the user status to lobby only if it was in home.
Applying this logic in the app won't work since I may encounter a race condition between 2 processes.
I would do something like this in mongo:

update({id:1, status:home}, {status: lobby})

This way I will receive the result (success or fail) if the update was successful, and it is atomic.

How can I do it in redis?

Upvotes: 0

Views: 1277

Answers (2)

Imaskar
Imaskar

Reputation: 2969

You can do it in a LUA procedure:

eval "local ks=redis.call('keys','user:*') for k=1,#ks do print(k) if (redis.call('hget',ks[k],'status') == KEYS[1]) then redis.call('hset',ks[k],'status',KEYS[2]) end end" 2 home lobby

127.0.0.1:6370> hset user:1 id 1 (integer) 1
127.0.0.1:6370> hset user:1 status outside (integer) 1
127.0.0.1:6370> hset user:2 id 2 (integer) 1
127.0.0.1:6370> hset user:2 status home (integer) 1
127.0.0.1:6370> eval "local ks=redis.call('keys','user:*') for k=1,#ks do print(k) if (redis.call('hget',ks[k],'status') == KEYS[1]) then redis.call('hset',ks[k],'status',KEYS[2]) end end" 2 home lobby
(nil)
127.0.0.1:6370> hgetall user:2 1) "id" 2) "2" 3) "status" 4) "lobby"
127.0.0.1:6370> hgetall user:1 1) "id" 2) "1" 3) "status" 4) "outside"

Upvotes: 0

Sheinbergon
Sheinbergon

Reputation: 3063

There's no update-by-query in Redis, like in other document stores/RDBMSs

You can either go with MULTI-EXEC transactions or EVAL / EVAL SHA to perform atomic updates and compose a batch of commands together

Redis uses a single thread for command processing (as of this moment), so evaluating a script would be performed atomically, and would probably be more straight forward approach than multi-exec.

Upvotes: 1

Related Questions