【问题标题】:Storing multiple nested objects in redis在redis中存储多个嵌套对象
【发布时间】:2017-11-28 08:27:40
【问题描述】:

我想在redis中存储多个复杂的json数据,但不知道如何

这是我的 json 结构

"users":{

        "user01":{username:"ally", email:"all@gmail.com"},
         "user02":{username:"user2".....}
        },

 "trucks":{
         "truck01":{reg_no:"azn102", make:"subaru" .......},
         "truck02":{reg_no:"kcaher3".....}
       }

我已经检查过了 THis question 它提供了一种存储用户的方法,但我想将用户(01、02)存储在用户内部,然后将卡车(01、02)存储在卡车中,这样如果我想检索用户,我可以简单地做

hmget users

卡车的类似情况

稍后我也想在用户中获取 user01,但对如何在 redis 中存储此类数据感到困惑

【问题讨论】:

    标签: json redis


    【解决方案1】:

    您可以使用 ReJSON Redis 模块并直接存储对象。 http://rejson.io/

    【讨论】:

      【解决方案2】:

      您可以像附加图片一样将数据保存在redis中。

      编辑

      示例代码为:

      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);
      
      
      
          }
      

      您可以对这些键执行 hmget 和 hmgetAll。

      【讨论】:

      • 您能否提供一段示例代码来保存,例如:用户,即我是否使用 hasmaps 或集合来实现这一点,就像您上面的图片一样
      • 我添加了示例
      • @AbhijeetBehare 这是题外话,但仅与 Redis 有关,如果您对此有任何信息,我将不胜感激:link
      【解决方案3】:

      我认为你最好使用HMSET 来保存密钥。

      就像您的情况一样,您可以创建一个名为“users”和“trucks”的HMSET。在 HMSET 中,您可以创建键(即字段),例如“user01”和“user02”。 由于这些键(如“user01”、“user02”等)能够在其中存储值,因此您可以将 JSON 对象的其余部分(即 {username:"ally", email:"all@gmail.com"})存储在 stringified 形式中。

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

      在此之后,您可以通过HGETALL 获取您的用户 列表(例如使用HGETALL users)。 同样,如果您需要获取“user01”的用户详细信息,则可以使用HGET,如HGET users user01。获取“user01”的值后,您可以解析该值并根据您的要求使用。

      【讨论】:

        【解决方案4】:

        Redis 是一个键值存储。您不能使用 Redis 链接两个数据结构。 最好使用 Mongo DB 或 Couch DB,它们是用于链接数据结构的文档数据库

        【讨论】:

        • 当然可以:只需将密钥存储到该对象所在的子对象(即“外键”)。
        • 没有。那是手动做的。 Redis 是一个键值存储。击键快速简单地恢复价值。不建议在不同类型的键中建立关系 le
        • 通常使用 memcached 完成。 Redis 只会让它变得更容易:)
        • 如果手动错误的可能性让您感到害怕,您可以封装它;)例如,celery 使用了一个类似的复杂结构,它们存储带有详细信息的“未确认”哈希和'unacked_index'(排序集)。
        • @DylanYoung 这是题外话,但仅与 Redis 有关,如果您有任何相关信息,我将不胜感激:link
        【解决方案5】:

        选项 1

        我认为如果您正在寻找一种独立于实现语言的方式,即在使用不同编程语言编写的系统的不同部分中期望相同的操作和结果,那么@Not_a_Golfer 's recommendation 最适合您的情况。

        选项 2

        但是,如果您碰巧只使用 Java 并且尚未运行 Redis 4.0,我建议您使用 Redisson 作为您的客户端库,以使您自己更轻松地完成这项工作。

        免责声明,我是Redisson 项目的成员,我在下面的观点是有偏见的。写这篇文章也是希望能传达给处于这种确切情况的其他人。

        Redisson 是一个客户端 Java 库,可让您将 Redis 作为内存数据网格进行操作。自然支持多维复杂对象。

        Redisson 为 Redis 数据类型提供标准 Java 接口,即 Redis hash 提供为 java.util.Mapjava.util.concurrent.ConcurrentMap,因此在您的情况下,用法很简单:

        //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);
        

        获取数据同样简单

        User user01 = users.get("user01");
        Truck truck02 = trucks.get("truck02");
        

        在 Redis 中,您会得到两个哈希值,一个称为 users,另一个称为 trucks,您会看到 JSON 字符串针对这些哈希对象中的指定字段名称进行存储。

        现在,您可能会争辩说这并不是一个真正的嵌套对象,这只是一个数据序列化。

        好的,让这个例子稍微复杂一点,看看有什么区别:如果你想保留所有驾驶过特定卡车的用户的列表,你可能还想轻松找出用户是哪辆卡车目前正在开车。

        我会说这些是相当典型的业务用例。

        这确实为数据结构增加了更多维度和复杂性。通常,您必须将它们分成不同的部分:

        • 您需要将TruckUser 映射到不同的散列以避免数据重复和一致性问题;

        • 您还需要为每辆卡车管理一个单独的列表来存储使用日志。

        在 Redisson 中,这些类型的任务处理得更加自然,无需考虑上述担忧。

        您可以像往常一样在 Java 中像这样简单地做:

        • 使用@REntity 注释注释您的User 类和Truck 类,并选择您自己的标识符生成器或说明符,这可以是字段的值。

        • 将 List 字段 (usageLog) 添加到 Truck 类。

        • 将 Truck 字段(currentDriving)添加到 User 类。

        这就是你所需要的。所以用法并不比你通常在 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);
        

        所以你最终得到的是每条记录都存储在Redis和一个哈希中,每条卡车记录都有一个独立的用户记录列表,其中包含使用过的用户记录,用户记录现在有他/她当前所在卡车的信息驾驶。所有这些事情都是使用对象引用而不是复制域记录来完成的。

        如您所见,Redisson 提供了一种解决方案,可以满足所有条件,并在此过程中消除麻烦。

        更多关于Redisson如何通过对象哈希映射和对象引用处理Redis中的多维复杂对象:

        【讨论】:

        • @Reddison_RuiGu 这是题外话,但仅与 Redis 有关,如果您对此有任何信息,我将不胜感激link
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-17
        相关资源
        最近更新 更多