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
Related
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.
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.
I am storing objects as hash ,for example: key-> customer:123 ,email->dk#gmail.com,mobile->828212,name->darshan etc...
Now is it possible in redis to query customers based on email without storing the cross relationship as set which is more of a workaround.
like for example,at the time of insertion of customer storing Set as key->email:dk#gmail.com value->customer:123 and so on.
Lets say if I have 100 fields in a hash, and i need to query 20 of them(like email)
it increases the count of keys in redis instance significantly if we create each entry of those fields in Sets as well.
Is there any other alternative or better approach?
Redis doesn't have inbuilt indexing/searching by fields because it is not a database but more like a data structures server(each key holds a data structure like set/list/map/sortedset/number of unique values etc), but if you are using redis 4.0 you can use the search module to accomplish it. The link is here.
Is it bad DB design to have an associative entity with multiple foreign keys?
In a scenario such as;
1 Truck is managed by 1 Team which goes to 1 particular route and has 1 Manager..etc
an associatve entity would be ideal in the above, is this bad design principle to do so?
First off an associative entity is needed for many-to-many relationships, so you need to use 0,1 or many in your description as opposed to 1 truck managed by 1 manager.
Secondly, associative entities have multiple foreign keys (one for every entity they have are connected with). An associative entity is essentially a RELATIONSHIP where both sides have a many carnality:
e.g. 0 or many trucks are managed by zero or many teams.
TEAM (TEAM_ID)
TRUCK (TRUCK_ID)
TRICK_MANAGEMENT_TEAMS (TEAM_ID, TRUCK_ID)
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.