How to delete Redis keys stored in a given Redis set? - redis

I want to delete Redis keys (and their data set) based on retreiving those keys from a specified set, for example:
HMSET id:1 password 123 category milk
HMSET id:2 password 456 category milk
HMSET id:3 password 789 category honey
SADD categories:milk 1 2
SADD categories:honey 3
Now I want to delete all the keys belongs to categories:milk (In that case: id:1 & id:2).
How can I do that?
Thanks.

I think this answer details the solution.
Basically, you have to retrieve the KEYS based on a pattern, looping through the results, and then using DEL to remove each one.

Related

Key-Range equivalent in Redis? Coming from DynamoDB

In DynamoDB I use a composite key to model the one-to-many relationship in a table:
User (Key) - Order (Range)
A typical set of records there is like:
John - Burger
John - Fries
Sue - Pizza
Sue - Soda
Looks like Redis only supports primary keys in which case this won't work because primary keys are unique. Is there a way to implement the above in Redis?
Redis supports two different data types which you can use to model your one-to-many relationship:
sets: unordered collections of unique strings;
sorted sets: collections of unique strings (members) ordered by an associated score.
To some extents, one could even use Redis lists, which are linked lists of string values.
Is there a way to implement the above in Redis?
Yes and it depends on how you are going to use that relationship. Here is how you can do that with Redis sets, for example:
SADD users:John Burger Fries
> 2
SADD users:Sue Pizza Soda
> 2

Redis design data structure based on secondary indices

Let's say I have to store the following object in my cache-
{
student_id: "student123",
school_id: "xyz123",
class_id: "class123"
}
How do I design my Redis data structure in a way where I can retrieve the object by any of the ids?
I tried doing a HSET command: HSET student123 school_id xyz123 class_id class123 but this creates a hash for the specific student_id. I also want to make sure that the search is in O(1). Thanks in advance!
To clarify, if I have to search by school_id, how would i go about that?
You need to use multiple keys indexes to get O(1) in your queries.
Consider using other data structures as well. Take a look at Secondary indexing with Redis, how to have relations many to many in redis and this other article on many to many.
Say, using sets, you add the {student123, xyz456, class789} entry as:
SADD student:student123 "xyz456 class789"
SADD school:xyz456 "student123 class789"
SADD class:class789 "xyz456 student123"
You may think "this will increase my memory usage a lot". It does indeed. It is the usual trade-off between memory and processing. Relational databases also do this when creating indexes. But Redis will give you sub-millisecond performance, and Redis uses multiple tricks to optimize memory usage, like ziplists, see https://redis.io/topics/memory-optimization.
What mix of data structures is best depends on the specifics of your use-case.
Consider removing the prefix in your keys if they are constant, just be consistent on the order you place them in the value.
SADD student:123 "456 789"
Keep in mind that sets and sorted sets allow unique members only. If you use one sorted set for students using student ID as score: ZADD students 123 "456 789", and then add another student at the same school-class with ZADD students 235 "456 789" this actually updated the score for "456 789", it didn't add a new value.

Search in Redis hash key

I have in Redis several similar keys like:
/article/200
/article/200?something
/article/200/something_else
I would like to retrieve all hashes that have the key like '/article/200%'.
Is that possible in Redis? And if yes, how?
If you mean values or entries inside the hash. Then it is not possible.
hset hash /article/200 1
hset hash /article/200?something 2
hset hash somethingelse 3
retrieving entries inside this hash is not possible. You need handle them in you application logic or you have to write a lua script for this.
If you want hashes i.e, keys to retrieve then it is possible.
hset /article/200 value1 1
hset /article/200?something value2 2
hset somethingelse value3 3
keys "/article/200*" will return /article/200 and /article/200?something
you can use scan ( http://redis.io/commands/scan ) or keys ( http://redis.io/commands/keys ) command to achieve the same.
keys "/article/200*" will give you all the keys matching the given pattern.
Keys are usually blocking and not advisable to use in production. So, use scan to achieve you requirement. Write a simple LUA script ( http://redis.io/commands/eval ) to achieve the same as atomic.

Is it possible to get all values for a Redis set in one operation?

Say I add two keys:
SET husband Bob
SET wife Alice
Then add these to a set:
SADD family husband wife
I can get the keys of this set with SMEMBERS family, which will return:
1) "wife"
2) "husband"
What I really want is the values:
1) "Alice"
2) "Bob"
Is this possible, in one operation? Essentially, I want to pipeline SMEMBERS with MGET.
SMEMBERS, but if the Set is big enough your database will take time to return all the members, during which it will be blocked. In such cases the use of SSCAN is recommended.
EDIT: missed the question itself :) use SORT family BY nosort GET *
The first thing you need to understand is Redis doesn't allow you to put a set in a set - no nested data structures. Likewise they are no vets and values in a set - only members which are strings in your case. This is why you can't "get the values".
It really sounds like the structure you are wanting is not a set but a hash. Using a hash will allow you do do exactly what you ask for.
hset family husband bob
hset family wife alice
And then to get what you call the values use hvals family.
This is the proper way to do it as it uses the right data structure, matches your terminology to the structure, and provides exaxtly what you want led without the performance penalties of sort. Further it allows you to use the various hash commands to select or update specific members of the family.
You could also use hgetall to use the mapping. That way your code knows Alice is the wife rather than the daughter.
Overall hashes are certainly the way to go here for virtually every reason.

Create an empty sorted set in Redis

Is there an easy way to create an empty sorted set in Redis? The documentation states
If key does not exist, a new sorted set with the specified members as
sole members is created, like if the sorted set was empty. If the key
exists but does not hold a sorted set, an error is returned.
However, it does not say you can create an empty sorted set. The following doesn't create an empty sorted set:
127.0.0.1:6379> zadd likes:0 1 one
(integer) 1
127.0.0.1:6379> exists likes:0
(integer) 1
127.0.0.1:6379> zcard likes:0
(integer) 1
127.0.0.1:6379> dbsize
(integer) 1
127.0.0.1:6379> zrem likes:0 one
(integer) 1
127.0.0.1:6379> exists likes:0
(integer) 0
The use case is reliably migrating data from another database to Redis, namely Postgres:
When a post is created, create an empty sorted set likes:<postId>
When a like is created, perform a zadd likes:<postId> <createdAt> <userId> if exists likes:<postId. Otherwise, query Postgres for the likes, and store them in likes:<postId>.
Creating an empty sorted set enables the assertion which removes an excessive query to Postgres when the first like is made on that post, yet still supports posts that have not been migrated over to Redis yet. This optimization will save our database 100k+ reads per day.
If the key doesn't exist, it behaves as an empty instance of any type. In your case, you can avoid the call to EXISTS likes:<postId> and assume the key is there, because the resulting behavior will be the same: when you add a member, the list will be created if it didn't exist until that point.