Reputation: 40624
I want to keep some user feedbacks in redis. Some users may give multiple feedbacks. The users are assigned numerical user id
Here is an example:
zadd feedbacks 1 feedback1 2 feedback2 3 feedback3 1 feedback4
In this case user #1 gave feedbacks feedback1 and feedback4, #2 feedback2 and #3 feedback3.
If I use ZRANGEBYSCORE feedbacks 1 1
I will be able to see the feedback from user #1:
1) "feedback1"
2) "feedback4"
However I want to store more than just the text. I want to be able to retrieve the timestamp
for example. Is there any way I can insert a hash vale to the key feedbacks
above?
Something likes zadd feedbacks 1 text:feedback1 timestamp:123456
Upvotes: 1
Views: 2172
Reputation: 6754
No, you cannot. Lists, sets, hashes and sorted sets only support Redis' string data type for the values.
You can stringify your field-value pairs though, using JSON or your preferred format.
ZADD feedbacks 1 "{\"text\":\"feedback1\",\"timestamp\":\"123456\""
Unless you need to modify a given field atomically, this approach should do.
And even in that case, you can use Lua scripts to achieve server-side JSON manipulation and updates. See How to nest a list into a structure in Redis to reduce top level? for a similar solution.
But you may want to query multiple ways: by user id, by timestamp, etc.
In that case, consider using regular keys to store the feedback object, say as a hash.
HSET feedbacks:feedback1 text feedback1 timestamp 123456 user 1 ...
And your indexes:
ZADD feedbacks-by-user 1 feedback1
ZADD feedbacks-by-timestamp 123456 feedback1
...
Say you want all feedbacks of a given user:
ZRANGEBYSCORE feedbacks-by-user 1 1
Then you go get the values for the returned keys. Of course, you may want to avoid the two round trips. Again, Lua script.
The script:
local keys = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[1])
for i, v in ipairs(keys) do
local k = {}
k[1] = v
k[2] = redis.call('HGETALL', 'feedbacks:'..v)
keys[i] = k
end
return keys
Usage:
> EVAL "local keys = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[1]) \n for i, v in ipairs(keys) do \n local k = {} \n k[1] = v \n k[2] = redis.call('HGETALL', 'feedbacks:'..v) \n keys[i] = k \n end \n return keys" 1 feedbacks-by-user 1
1) 1) "feedback1"
2) 1) "text"
2) "feedback1"
3) "timestamp"
4) "123456"
5) "user"
6) "1"
2) 1) "feedback4"
2) 1) "text"
2) "feedback4"
3) "timestamp"
4) "465465"
5) "user"
6) "1"
You can similarly query for a range of timestamps.
You can mix and match your queries using ZINTERSTORE
or ZUNIONSTORE
.
You may be interested in How to store in Redis sorted set with server-side timestamp as score?. You can make a nice Lua script to take care of creating the hash, and the secondary index entries, all in one go with redis-server-side timestamping.
Finally, whenever using Lua on Redis, consider to load the script and use EVALSHA
.
Upvotes: 4