21

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:"all@gmail.com"},
         "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

Geoff
  • 6,277
  • 23
  • 87
  • 197

5 Answers5

10

You can use the ReJSON Redis Module and store the objects directly. http://rejson.io/

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
6

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("all@gmail.com");

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:

Mayank Jain
  • 369
  • 5
  • 21
Redisson_RuiGu
  • 1,012
  • 10
  • 13
  • @Reddison_RuiGu This is off topic but related to Redis only and I appreciate if you have any information on this [link](https://stackoverflow.com/q/57572975/3110101?stw=2) – pan1490 Sep 05 '19 at 12:02
5

You can save data in redis like in attached images.In this images i have made a structure for you

for user data

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", "ally@abc.com");
        jsonObject3.put("username", "xyz");
        jsonObject3.put("email", "xyz@abc.com");
        jsonObject1.put("user01", jsonObject2);
        jsonObject1.put("user02", jsonObject3);
        jsonObject.put("users", jsonObject1);


    // json is -- >  {"users":{"user02":{"email":"xyz@abc.com","username":"xyz"},"user01":{"email":"ally@abc.com","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.

Abhijeet Behare
  • 597
  • 1
  • 7
  • 21
  • could you provide a sample piece of code to save eg: the users, that is do i use hasmaps or sets to achieve this like in your picture above – Geoff Jun 27 '17 at 12:18
  • i have added sample example – Abhijeet Behare Jul 04 '17 at 10:58
  • @AbhijeetBehare This is off topic but related to Redis only and I appreciate if you have any information on this:[link](https://stackoverflow.com/q/57572975/3110101?stw=2) – pan1490 Aug 23 '19 at 06:13
5

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:"all@gmail.com"}) of JSON object in stringified form.

For example: HMSET users user01 "{\"username\":\"ally\",\"email\":\"all@gmail.com\"}"

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.

Mayank Jain
  • 369
  • 5
  • 21
3

Redis is a key value store. You cannot link two data structures using Redis. Better use Mongo DB or Couch DB which are document databases meant to link data structures

Srini Sydney
  • 564
  • 8
  • 17
  • Sure you can: just store the key to the sub-object where the object would have been (i.e. a "foreign key"). – DylanYoung May 10 '19 at 14:09
  • No . That's doing it manually. Redis is a key value store. Hit the key get the value back fast simple. Building relationships within different type of keys not advisable le – Srini Sydney May 11 '19 at 15:12
  • It's quite commonly done with memcached. Redis only makes it easier :) – DylanYoung May 14 '19 at 20:26
  • If the possibility of manual error is what scares you, you can encapsulate it ;) A similar complex construct is used by celery for example, where they store both an 'unacked' hash with detailed info and an 'unacked_index' (a sorted set). – DylanYoung May 14 '19 at 20:27
  • It is true though, that redis won't maintain referential integrity for you, but that wasn't the question – DylanYoung May 14 '19 at 20:30
  • If you would like a reference implementation, I can provide one. – DylanYoung May 14 '19 at 20:31
  • 1
    @DylanYoung This is off topic but related to Redis only and I appreciate if you have any information on this:[link](https://stackoverflow.com/q/57572975/3110101?stw=2) – pan1490 Aug 23 '19 at 06:15