在Redis中存储多个嵌套对象

21
我希望能够在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".....}
       }

我已经查看了这个问题,它提供了一种存储用户的方法,但我想把用户(01, 02)存储在users里面,然后把卡车(01, 02)存储在卡车中,这样如果我想检索用户,我只需执行

hmget users

对于卡车的情况也类似

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

5个回答

10

6

选项1

如果您正在寻找一种与实现语言无关的方式,即期望在使用不同编程语言编写的系统的不同部分中获得相同的操作和结果,则建议采用@Not_a_Golfer's recommendation

选项2

但是,如果您只使用Java,并且尚未运行Redis 4.0,则建议使用Redisson作为客户端库,以使此工作更加轻松。

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

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

Redisson使用标准Java接口提供Redis数据类型,例如Redis哈希提供了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字符串存储在这些哈希对象的指定字段名中。
现在,你可能会争辩说这并不是真正的嵌套对象,这只是一种数据序列化。
好吧,让我们让例子更加复杂,以看到区别:如果你想保留所有开过特定卡车的用户列表,你也可能想轻松地找出哪个卡车当前正在被用户驾驶。
我会说这些都是相当典型的业务用例。
这确实增加了数据结构的维度和复杂性。通常你需要将它们分成不同的部分:
- 你需要将“Truck”和“User”映射到不同的哈希对象中,以避免数据重复和一致性问题; - 你还需要管理每辆卡车的单独列表,以存储使用日志。
在Redisson中,这些类型的任务处理更自然,且无需考虑上述问题。
你可以像在Java中一样简单地做到这一点:
1.使用@REntity注释您的“User”类和“Truck”类,并选择一个标识符生成器或指定您自己,这可以是字段的值。
2.向“Truck”类添加List字段(usageLog)。
3.向“User”类添加Truck字段(currentlyDriving)。
这就是你需要的全部。因此,使用方式不比在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相关,如果你有任何关于此的信息,我会很感激。[链接] (https://stackoverflow.com/q/57572975/3110101?stw=2) - pan1490

5
我认为最好使用HMSET来保存键。在您的情况下,您可以创建一个名为“users”和“trucks”的HMSET。在该HMSET中,您可以创建键(即字段),例如“user01”和“user02”。由于这些键(如“user01”,“user02”等)能够存储值,因此您可以将JSON对象的其余部分(即{username:“ally”,email:“all@gmail.com”})以字符串化形式存储。
例如:HMSET users user01 "{\"username\":\"ally\",\"email\":\"all@gmail.com\"}" 之后,您可以通过HGETALL(例如使用HGETALL users)获取您的users列表。同样,如果您需要获取“user01”的用户详细信息,则可以使用HGET,如HGET users user01。获取“user01”的值后,您可以解析该值并根据需要使用。

5
您可以像附图中所示的那样在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操作。

你能提供一段保存用户的示例代码吗?我应该使用哈希映射还是集合来实现,就像你上面的图片中那样? - Geoff
我已经添加了示例。 - Abhijeet Behare
@AbhijeetBehare 这个话题与 Redis 有关,虽然不是正题,但我很感激如果你有任何相关信息:链接 - pan1490

3

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


当然可以:只需将对象的键存储到子对象的位置(即“外键”)。 - DylanYoung
这在 memcached 中非常常见。Redis 只是让它更容易 :) - DylanYoung
虽然这是真的,Redis不会为您维护引用完整性,但这不是问题所在。 - DylanYoung
如果您需要参考实现,我可以提供一个。 - DylanYoung
1
@DylanYoung 这个话题有些偏离主题,但与Redis有关。如果您有任何相关信息,请让我知道:链接 - pan1490
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接