How to combine Redis commands 'expire' and 'sadd' into one command? - redis

I need to create a set in Redis:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "World"
2) "Hello"
But I need to set expire time for the key myset.
In other words I need a command kind of expire sadd myset... (like SETEX for string values).
Is there any way to execute these commands per one request to Redis server?

There is no built-in command to do this. What you may do is; using transactions. As it is stated in the documentation;
All the commands in a transaction are serialized and executed sequentially. It can never happen that a request issued by another client is served in the middle of the execution of a Redis transaction. This guarantees that the commands are executed as a single isolated operation.
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SADD mynewset a b c d e f g
QUEUED
127.0.0.1:6379> SADD mynewset f g h j k l
QUEUED
127.0.0.1:6379> EXPIRE mynewset 86400
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 7
2) (integer) 4
3) (integer) 1
127.0.0.1:6379> TTL mynewset
(integer) 86394
127.0.0.1:6379>

There is also the possibility of using a Lua script to tie the two commands together:
127.0.0.1:6379> EVAL "redis.call('SADD', KEYS[1], unpack(ARGV)) redis.call('EXPIRE', KEYS[1], 3600)" 1 myset a b c d e
(nil)
127.0.0.1:6379> SMEMBERS myset
1) "c"
2) "d"
3) "a"
4) "b"
5) "e"
127.0.0.1:6379> TTL myset
(integer) 3596

Related

Reset value for key in redis

I am storing some values in redis like for key: 1 the value will be
{"counter":1,"counter1":2}
Now I need to reset value of counter while the counter1 should be remaining same.
To increase counter I am use the command SETEX mykey 60 redis .
But it will also reset the value of counter1. So is there any way I can reset one value for a single key.
Let me know if I need to add some more info.
Instead of string you may use hash, then it will be easy. you can increment by some other value, delete counter etc etc. Each key in your json will be hash field.
127.0.0.1:6379> hset mykey counter 1 counter1 2
(integer) 2
127.0.0.1:6379> hgetall mykey
1) "counter"
2) "1"
3) "counter1"
4) "2"
127.0.0.1:6379> hset mykey counter 25
(integer) 0
127.0.0.1:6379> hgetall mykey
1) "counter"
2) "25"
3) "counter1"
4) "2"
127.0.0.1:6379> HINCRBY mykey counter 15
(integer) 40
127.0.0.1:6379> hgetall mykey
1) "counter"
2) "40"
3) "counter1"
4) "2"
127.0.0.1:6379>

Can we add Value in Redis List with Expiration Time in C#?

I am using Redis queue and adding the data using ListLeftPush and reading data using ListRightPop. It works fine I am able to get the data. But what if data has not popped out? Can we delete old data? or Can we add Value in Redis List with Expiration Time?
How to add time limit for each value while using ListLeftPush command in C#?
It is not possible to add expire time for individual value for the sake of keeping redis simple and fast.
you can only add expire time for individual keys i.e in ur case it is for whole list.
No redis doesn't support that. Expiration is available only for the top level keys. The closes data type/solution for your case would be sorted sets.
You put your expiration time(timestamp) as score while adding to sorted set(ZADD)
Instead of LPOP you use ZPOPMAX to get "to be last expired" element.
Periodically you may use ZREMRANGEBYSCORE to remove expired elements.
For the demonstration i used smaller numbers as expiration dates.
127.0.0.1:6379> ZADD myset 15 "a"
(integer) 0
127.0.0.1:6379> ZADD myset 25 "b"
(integer) 0
127.0.0.1:6379> ZADD myset 35 "c" 45 "d" 55 "e"
(integer) 0
127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
1) "a"
2) "15"
3) "b"
4) "25"
5) "c"
6) "35"
7) "d"
8) "45"
9) "e"
10) "55"
127.0.0.1:6379> ZPOPMAX myset
1) "e"
2) "55"
127.0.0.1:6379> ZREMRANGEBYSCORE myset -1 15
(integer) 1
127.0.0.1:6379> ZRANGE myset 0 -1
1) "b"
2) "c"
3) "d"
127.0.0.1:6379>

How to get number of elements in a redis hash map?

Assuming that myhash is like:
redis 127.0.0.1:6379> HSET myhash field1 "foo"
(integer) 1
redis 127.0.0.1:6379> HSET myhash field2 "bar"
(integer) 1
redis 127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
How can I get number of myhash elements, that is 2, from redis-cli?
I'm learning redis from this tutorial but could not find my answer there.
You can use the HLEN command. Taken directly from the documentation at redis.io:
redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HLEN myhash
(integer) 2
redis>

Direct search for a key-value pair in redis

In a redis-cli session:
127.0.0.1:6379> SET somekey "Greetings"
OK
127.0.0.1:6379> SET somekey "Mortal"
OK
127.0.0.1:6379> EXISTS somekey
(integer) 1
I am looking for a function SOMEFUNC that searches for a key and a value. Perhaps something such as:
127.0.0.1:6379> SOMEFUNC "somekey:Greetings"
(integer) 1
127.0.0.1:6379> SOMEFUNC "somekey:Ave"
(integer) 0
It's all driven by a program, so I could use SSCAN on the key and compare, but I'm wondering if there is SOMEFUNC that will do this directly, as the statements above illustrate.
As noted by #MrWiggles, there is no such SOMEFUNC for Strings. On top of the two alternatives that he suggests, another that could get you pretty close is using Hashes instead. Consider the following:
127.0.0.1:6379> HSET somehash "Greetings" ""
(integer) 1
127.0.0.1:6379> HEXISTS somehash "Greetings"
(integer) 1
127.0.0.1:6379> HEXISTS somehash "Mortal"
(integer) 0
127.0.0.1:6379> HEXISTS someotherhash "Ave"
(integer) 0
Sets can also do the same trick:
127.0.0.1:6379> SADD someset "Greetings"
(integer) 1
127.0.0.1:6379> SISMEMBER someset "Greetings"
(integer) 1
127.0.0.1:6379> SISMEMBER someset "Mortal"
(integer) 0
127.0.0.1:6379> SISMEMBER someotherset "Ave"
(integer) 0
That said, note that Hashes & Sets have memory overheads (just like Strings). For 100,000 String/Hash/Set keys, here's what my local Redis' INFO MEMRORY reports for used_memory(_human):
Strings: 9594616 (9.15M)
Hashes: 11194616 (10.68M)
Sets: 25594616 (24.1M)
The real question, however, is why you want to keep everything in separate keys. Unless there's a compelling reason not to do so in your use case, consider a single Hash as a mini-store for all of your "keys" (fields) and values, e.g.:
127.0.0.1:6379> HSET minikv somekey Greetings
(integer) 1
127.0.0.1:6379> HSET minikv anotherkey Human
(integer) 1
...
In terms of your original question, this will bring you back to square one - meaning you'll have to read (HGET minikv somekey) and compare in your app or, my favorite, wrap it in Lua to do it in one call, perhaps like this:
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv somekey Greetings
(integer) 1
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv somekey Mortal
(integer) 0
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv anotherkey Mortal
(integer) 0
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv anotherkey Human
(integer) 1
The nice thing about using this minikv Hash is the footprint - a 100K Hash INFO memory:
used_memory:8519088
used_memory_human:8.12M
There is nothing built in to Redis that will do this for you.
A couple of ways of achieving this are:
Fetch the value of the key back into your application and then check the value to see if it equals what you want it to
Use a Lua script to do this on the redis server

Numerical operation in Redis sort

As in the doc http://redis.io/commands/sort
SORT mylist BY weight_*
What I would want to do is something like
SORT mylist BY (weight_* + vote_*)
Is that possible to do this just by Redis?
You can use Lua to build each sum_* key and sort by those:
redis 127.0.0.1:6379> sadd myset 1 2 3
(integer) 0
redis 127.0.0.1:6379> mset weight_1 1 weight_2 2 weight_3 3
OK
redis 127.0.0.1:6379> mset vote_1 1 vote_2 2 vote_3 0
OK
redis 127.0.0.1:6379> eval "for i in ipairs(redis.call('smembers', KEYS[1])) do redis.call('set', 'sum_' .. i, redis.call('get','weight_' .. i) + redis.call('get', 'vote_' .. i)) end;" 1 myset
(nil)
redis 127.0.0.1:6379> sort myset by sum_*
1) "1"
2) "3"
3) "2"