Search code examples
redisspring-data-redisredis-cli

Delete Specific value from redis hash field value


I have redis hash, i want to delete the specific value of field.

127.0.0.1:6379> hset abc 12 34,121
(integer) 1
127.0.0.1:6379> hgetall abc
1) "12"
2) "34,121"

I only want to delete 121 from value.

I know hdel command deletes the field but not specific value of field.

127.0.0.1:6379> hdel abc 12
(integer) 1
127.0.0.1:6379> hgetall abc
(empty array)

this deletes the whole field for hash.


Solution

  • Hashes in Redis store Redis Strings. Redis has no idea that the value contains a comma-separated list of number. It just sees a String. You'll need to pull the value out, modify it in code, then write it back in.

    If you want to do this atomically, you'll need to look at using transactions— which give you an optimistic locking mechanism—or write a Lua script. Here's how to do it with a transaction.

    First, WATCH the key abc. If during the transaction this key is changed, the transaction will fail and you'll need to handle it in your code.

    127.0.0.1:6379> WATCH abc
    OK
    

    Now you need to fetch the value of the field from the key and write code to parse it and remove the offending value:

    127.0.0.1:6379> HGET abc 12
    "34,121"
    

    To write the value out and make sure that nobody else has done the same, start a transaction using MULTI, HSET the new value for the field, and call EXEC:

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> HSET abc 12 34
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) (integer) 0
    

    If nobody has changed abc, EXEC should return the results of the commands that you have queued, in this case the number of fields that were added to the Hash. If somebody has changed the key abc that it will return (nil) instead and you'll need to try again in your code.

    If it's an option, you might want to consider using RedisJSON to store these values as JSON in Redis instead. Then, you could simply modify the array using JSONPath queries:

    127.0.0.1:6379> JSON.SET abc $ '{ "12": [ 34, 121 ]}'
    OK
    127.0.0.1:6379> JSON.DEL abc "$.12[?(@ == 121)]"
    (integer) 1
    127.0.0.1:6379> JSON.GET abc
    "{\"12\":[34]}"
    

    Easier to code and no need to mess about with transactions or Lua.