I would like to store multiple complex json data in redis but am not sure how
THis is my json structure
"users":{
"user01":{username:"ally", email:"[email protected]"},
"user02":{username:"user2".....}
},
"trucks":{
"truck01":{reg_no:"azn102", make:"subaru" .......},
"truck02":{reg_no:"kcaher3".....}
}
I have checked on THis question which provides a way to store the users but i would like to store users(01, 02) inside users then trucks(01, 02) in trucks so that if i want to retrieve users i can simply do
hmget users
and similar case for trucks
Later i would also want to get user01 in users but am confused on how to store such data in redis
Unlike document-oriented databases, Redis is not designed to have nested objects in it. However, sometimes needs to store the complex object, so how to do it if it's not actually supported by Redis? The answer is short: store the preferred object as a string or hash type.
Redis doesn't support nested data structures, and specifically it doesn't support a Hash inside a Hash :) You basically have a choice between two options: either serialize the internal Hash and store it in a Hash field or use another Hash key and just keep a reference to it in a field of the outer Hash.
Object Storing Procedure. In the Redis, Everything can be stored as only key-value pair format. Key must be unique and storing an object in a string format is not a good practice anyway. Objects are usually stored in a binary array format in the databases.
RedisJSON stores the data in a binary format which removes the storage overhead from JSON, provides quicker access to elements without de-/re-serialization times. To use RedisJSON you need to install it in your Redis server or enable it in your Redis Enterprise database.
You can use the ReJSON Redis Module and store the objects directly. http://rejson.io/
Option 1
I think if you are searching for an implementation language independent way, i.e. the same operation and result are expected in different parts of the system written in different programming languages, then @Not_a_Golfer 's recommendation is best suited for your case.
Option 2
However, if you happened to be using Java only and you are not running Redis 4.0 yet, I would recommend you use Redisson as your client side library to make this job a lot easier for yourself.
Disclaimer, I am a member of the Redisson project, my view below is biased. It is also written in a hope that it can reach to others who are in this exact situation.
Redisson is a client side Java library that lets you operate Redis as an In-Memory Data Grid. Multi-dimensional complex objects are naturally supported.
Redisson provides Redis data types with standard Java interfaces, i.e. Redis hash
is provided as java.util.Map
and java.util.concurrent.ConcurrentMap
so in your case the usage would be simply be:
//lets imagine you have a builder that creates users
User user01 = new User();
user01.setUsername("ally");
user01.setEmail("[email protected]");
User user02 = new User();
user02.setUsername("user2");
user02.setEmail("...");
//You get a Redis hash handler that works as a standard Java map
Map<String, User> users = redisson.getMap("users");
//This is how you put your data in Redis
//Redisson serialize the data into JSON format by default
users.put("user01", user01);
users.put("user02", user02);
//the same works for trucks
Truck truck01 = new Truck();
truck01.setRegNo("azn102");
truck01.setMake("subaru");
Truck truck02 = new Truck();
truck02.setRegNo("kcaher3");
truck02.setMake("...");
//The same as above
Map<String, Truck> trucks = redisson.getMap("trucks");
trucks.put("truck01", truck01);
trucks.put("truck02", truck02);
Getting your data out is just as easy
User user01 = users.get("user01");
Truck truck02 = trucks.get("truck02");
In Redis, what you would get is two hashes, one called users
and another called trucks
, you would see JSON strings are stored against specified field names in these hash objects.
Now, you may argue this is not really a nested objects, this is just a data serialization.
OK, lets make the example a little more complex to see the difference: What if you want to keep a list of all the users who had driven a particular truck, you may also want to easily find out which truck a user is currently driving.
I would say these are fairly typical business use cases.
That really adds more dimensions and complexity to the data structures. Normally you would have to break them in to different pieces:
You would need the Truck
and User
be mapped to a different hash to avoid data duplication and consistency issue;
You would also need to manage a separate list for each truck to store the usage log.
In Redisson, these type of tasks are handled more naturally and without bearing the aforementioned worries in mind.
You would simply do, as you would normally, in Java like this:
Annotate your User
class and Truck
class with @REntity annotation, and choose an identifier generator or specifier your own, this could be the value of a field.
Add a List field (usageLog) to Truck class.
Add a Truck field (currentlyDriving) to User class.
That's all you need. So the usage is not much more than you would normally do in Java:
//prepare the service and register your class.
RLiveObjectService service = redisson.getLiveObjectService();
service.registerClass(User.class);
service.registerClass(Truck.class);
Truck truck01 = new Truck();
truck01.setRegNo("azn102");
truck01.setMake("subaru");
//stores this record as a Redis hash
service.persist(truck01);
User user02 = new User();
user02.setUsername("user2");
user02.setEmail("...");
//stores this record as a Redis hash
service.persist(user02);
//assuming you have invoked setUsageLog elsewhere.
truck01.getUsageLog().add(user02);
user02.setCurrentlyDriving(truck01);
//under normal circumstance keeping a Redis hash registry is not necessary.
//the service object can be used for this type of look up.
//this is only for demonstration.
Map<String, Truck> trucks = redisson.getMap("trucks");
trucks.put("truck01", truck01);
Map<String, User> users = redisson.getMap("users");
users.put("user02", user02);
So what you get in the end is each record is stored in Redis and a hash, and each truck record keeps an independent list of user records who has used it, user record now has information of the truck he/she is currently driving. All of these things are done using object references instead of duplicating the domain records.
As you can see Redisson provides a solution that ticks all the boxes and takes the headaches away during the process.
For more information relating to how Redisson handles multi-dimensional complex objects in Redis through object hash mapping and object referencing:
I think better you can use HMSET to save keys.
Like in your case you can create a HMSET
with name "users" & "trucks". In that HMSET
you can create keys (i.e. fields) like "user01" and "user02".
As these keys(like "user01", "user02" etc) are able to store value in it, so you can store your rest (i.e. {username:"ally", email:"[email protected]"}
) of JSON object in stringified form.
For example: HMSET users user01 "{\"username\":\"ally\",\"email\":\"[email protected]\"}"
After this you can get your users list by HGETALL (like by using HGETALL users
).
Similarly, if you need to fetch user details of "user01" then you can use HGET like HGET users user01
. After fetching value of "user01" you can parse that value and use according to your requirement.
You can save data in redis like in attached images.
EDIT
The sample code is :
public void saveInRedis(Jedis jedis) throws JSONException{
JSONObject jsonObject=new JSONObject();
JSONObject jsonObject1=new JSONObject();
JSONObject jsonObject2=new JSONObject();
JSONObject jsonObject3=new JSONObject();
jsonObject2.put("username", "ally");
jsonObject2.put("email", "[email protected]");
jsonObject3.put("username", "xyz");
jsonObject3.put("email", "[email protected]");
jsonObject1.put("user01", jsonObject2);
jsonObject1.put("user02", jsonObject3);
jsonObject.put("users", jsonObject1);
// json is -- > {"users":{"user02":{"email":"[email protected]","username":"xyz"},"user01":{"email":"[email protected]","username":"ally"}}}
System.out.println("json is --- > "+jsonObject);
JSONObject parse=new JSONObject(jsonObject.toString());
JSONObject parseJson=parse.getJSONObject("users");
JSONObject parseJson2=parseJson.getJSONObject("user02");
JSONObject parseJson3=parseJson.getJSONObject("user01");
Map<String, String> map=new HashMap<>();
Map<String, String> map1=new HashMap<>();
map.put("email", parseJson2.getString("email"));
map.put("username", parseJson2.getString("username"));
map1.put("email", parseJson3.getString("email"));
map1.put("username", parseJson3.getString("username"));
jedis.hmset("users:user01", map);
jedis.hmset("users:user02", map1);
}
you can do hmget and hmgetAll on that keys.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With