V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jiobanma
V2EX  ›  Java

关于数据聚合与 graphQL 的使用

  •  
  •   jiobanma ·
    banmajio · 2020-08-11 23:20:46 +08:00 · 3190 次点击
    这是一个创建于 1569 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有个需求,比如我通过 userid 查数据库映射到 userBean 中,然后我还需要通过 userBean 中传回来的内容中的 groupId 查数据库映射到 groupBean 中。这个时候我可以获取到两个 java 对象( user 、group )。 普遍的做法是将两个对象塞到一个 List 中,返回给前端,前端自己过滤和拼装渲染。 其实前端想要是一个聚合后的 json 。 比如按照之前的做法我们返回给前端的 json 是这样的: { "user": { "userid": 111, "name": "张三", "age": "12", "sex": "男" }, "group": { "groupid": 222, "name": "学习组", "des": "学习小组" } }

    但是现在前端想要的格式其实是 { "user": { "userid": 111, "name": "学习组", "age": "12", "sex": "男", "groupid": 222 } }

    当然服务端可以通过定义一个只包含这些字段的 bean 出来,然后将两次查询到的结果分别 set 进去。但是这样会造成产生了很多返回结构体的 bean 出现。

    目前了解了一下 graphQL,但是感觉后端加入这个框架写的很麻烦,网上没有太多 springboot+graphQL 的 demo 。而且感觉写法也不太简单,可能是我太菜的原因。

    问下大家,后端实现数据聚合还有哪些思路? 或者是使用 graphQL 有哪些 demo 可以参考。今天看这块内容已经自闭一天了。

    20 条回复    2020-08-12 15:48:44 +08:00
    Mithril
        1
    Mithril  
       2020-08-12 00:23:45 +08:00   ❤️ 1
    这种需求 GraphQL 可以直接解决。你定义 GraphQL 对象的时候直接用 User 里面嵌套一个 Group,前端需要从 User 里面获取所属 Group 的时候直接拿这个对象就可以了,GraphQL 会给它填进去。
    当然很多时候你需要自己写 DataLoader 。
    你如果不能用纯 Rest API 完成接口设计,那么多数是前端需要依靠后端来聚合数据。大概率是因为性能原因没办法在前端做聚合。GraphQL 本身可以帮你做一些简单的聚合,同时也可以直接减少请求次数。但是最终你很可能还是要自己写一些 DataLoader 或者构造一些用来做 VM 的 Graph Type 。
    对于后端来说,用 GraphQL 不会带来太多便利,该写的还是要写。只是前端可以一定程度上自行决定返回的数据结构,你也省了很多沟通成本,提升的是整个项目的效率。
    lihongming
        2
    lihongming  
       2020-08-12 00:33:15 +08:00 via iPhone
    私以为,GraphQL 不是给后端用的,而是应该由前端自己写的。

    现在的前端早已不是那个切图仔了,大前端至少要负责到直接对外暴露的 API 那一级
    optional
        3
    optional  
       2020-08-12 09:04:23 +08:00 via Android
    graphql 的格式就是前者,而不是后者。
    jiobanma
        4
    jiobanma  
    OP
       2020-08-12 09:07:59 +08:00
    @Mithril #1 问下大佬,我想这么做:接口还是传统的 rest 的接口,然后在 controller 中使用 graphql 对数据库中查询出来的数据进行聚合 聚合为一个 json 返回给前端。这样可以实现吗? 因为对 graphql 了解的不是太多,看到网上的 demo 大多都是接口传入的是类似于 json 的 graphql 的语法。
    jiobanma
        5
    jiobanma  
    OP
       2020-08-12 09:08:28 +08:00
    @optional #3 那是说,graphql 无法聚合为后者那样的格式吗?
    optional
        6
    optional  
       2020-08-12 09:36:00 +08:00 via Android
    就像你上面说的,可以再映射一下数据格式,其实这很好的方案,graphql 直接给前端也有其它的坏处,中间加一层可以解决不少问题。而且这些映射有现成的工具可以配置。
    jiobanma
        7
    jiobanma  
    OP
       2020-08-12 09:40:47 +08:00
    @optional #6 主要是找不到好的 demo 看官网有点看不太懂 水平有些差
    ianva
        8
    ianva  
       2020-08-12 09:49:22 +08:00
    java 里似乎没什么好方案,我们这边全转到 node.js ,用 Apollo 了
    Mithril
        9
    Mithril  
       2020-08-12 09:50:42 +08:00
    @jiobanma 你这个做法是不行的。你没法从一个 Rest Controller 里面直接调用 GraphQL 。GraphQL 也不是拿来做数据聚合用的。
    它的核心就是你说的那个 JSON 语法,通过 POST 请求过来的 JSON 被解析后,GraphQL 会去调用对应的 Query,然后你这些手写的 Query 会调用和聚合相关的 Type 。
    这一个链条里的 Query 和 Graph Type 都是你自己手写的,和 Rest API 用的类型是不一样的。比如按你的例子来说,你在 User 里面挂个 Group 。一般的 Rest API 只会从 User 里面返回一个 Group ID 。但你如果做成 GraphQL 接口的话,你需要自己写把这个 Group ID 转换成 Group 对象的查询。
    GraphQL 会帮你在需要的时候去调用这个查询而已。
    jiobanma
        10
    jiobanma  
    OP
       2020-08-12 09:53:26 +08:00
    @Mithril #9 但是网上的一个 demo 他的写法是这样的:
    ```
    public static void main(String[] args) {
    String query1 = "{users(page:2,size:5,name:\"john\") {id,sex,name,pic}}";
    String query2 = "{user(id:6) {id,sex,name,pic}}";
    String query3 = "{user(id:6) {id,sex,name,pic},users(page:2,size:5,name:\"john\") {id,sex,name,pic}}";

    GraphQLSchema schema = new HelloGraphql().getSchema();

    Object result1 = GraphQL.newGraphQL(schema).build().execute(query1).getData();
    Object result2 = GraphQL.newGraphQL(schema).build().execute(query2).getData();
    Object result3 = GraphQL.newGraphQL(schema).build().execute(query3).getData();

    // 查询用户列表
    System.out.println(result1);
    // 查询单个用户
    System.out.println(result2);
    // 单个用户、跟用户列表一起查
    System.out.println(result3);
    }
    ```
    这里得到的 result 不就是我需要的结果吗? 我把这个结果返回 不就是我需要的需求吗?
    Mithril
        11
    Mithril  
       2020-08-12 09:58:43 +08:00
    @jiobanma 是的。我说的你不能在 Rest Controller 里面干这个事主要是因为这是违背 Restful 的设计原则的。单独做一个 GraphQL 用的 Controller 就可以了。
    你可以去看一下它的 HelloGraphql 的 Schema 和 Type 是怎么写的,那个是核心。
    jiobanma
        12
    jiobanma  
    OP
       2020-08-12 10:01:48 +08:00
    @Mithril #11 好的 谢谢啦
    optional
        13
    optional  
       2020-08-12 10:04:34 +08:00 via Android
    @Mithril 实践下来,前面加一层是很有好处的,graphql 还真挺适合做聚合,做接口反倒一堆问题,监控,缓存,日志之类的
    Mithril
        14
    Mithril  
       2020-08-12 10:10:28 +08:00
    @optional 其实做聚合也是一样,简单查询还行,复杂一点的你就得写 DataLoader 。
    其实做接口这个事,不管你是 Restful 也好,GraphQL 也好,瞎怼也好,都只是个形式和工具。该做的事一件也不会少。
    各有优缺点而已。也不是说上了 GraphQL 就万能了,只是说如果聚合和标准化是你的痛点的话,那 GraphQL 可以帮你尽量避开这些坑,但其他的坑该有也还是会有的。
    jiobanma
        15
    jiobanma  
    OP
       2020-08-12 10:11:57 +08:00
    @Mithril #14 嗯嗯 先试试吧 比较还在调研阶段
    Mithril
        16
    Mithril  
       2020-08-12 10:19:58 +08:00
    @jiobanma 嗯。你试的时候注意一下,不要光看例子那些从内存里直接返回数据的,试着把查询打到数据库里。如果你一次返回一个对象数组,然后数组里的对象还嵌套了查询,数据库没准直接就炸了。
    Data Loader 就是用来解决这个问题的。
    这俩试过了,GraphQL 做查询的坑基本就趟过去了。然后就是 Mutation,权限,Log 等等。。。
    jiobanma
        17
    jiobanma  
    OP
       2020-08-12 10:26:54 +08:00
    @Mithril #16 Data Loader 是个什么东西啊
    Mithril
        18
    Mithril  
       2020-08-12 10:56:08 +08:00
    @jiobanma GraphQL 的一个功能,你看一下 Demo 一般都有。
    jilu171990
        19
    jilu171990  
       2020-08-12 12:38:50 +08:00
    @lihongming 哈哈,让前端写 graphQL 的结果往往就是直接被爆库。。。
    lihongming
        20
    lihongming  
       2020-08-12 15:48:44 +08:00 via iPhone
    @jilu171990 前端直接搞库,后端真啥都不管了啊?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2766 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 15:26 · PVG 23:26 · LAX 07:26 · JFK 10:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.