GraphQL Java:分组 SQL 和映射

GraphQL Java: Grouping SQL and Mapping

我正在构建 graphql-java spring 启动应用程序。 可以说我有这个模式:

type Foo {
id: ID! name: String bars: [Bar]
}
type Bar {
id: ID! name: String
}
query{
  foo(arg: String): [Foo]
}

在 BE 上我使用的是 JOOQ pojos。

当前获取所有 Foos,然后对于每个 foo,所有 Bars 都通过另一个查询获取。 我想用一个查询来做到这一点:

select * from foo 
left join bar on foo.id = bar.foo_id;

你知道如何实现吗?我是 GraphQL 的新手。

技术栈: Spring 开机 JOOQ graphql-java graphql-java-工具

嵌套集合的经典 SQL 策略

在您的简单示例中,LEFT JOIN 绝对是一个选项。这就是像 JPA/Hibernate 这样的 ORM 在获取嵌套集合时在幕后所做的事情。该策略有一些缺点:

  • 存在数据重复。对于每个 BAR(子 table),您将复制匹配的 FOO(父 table)的数据。这可能会导致大量开销以通过网络传输。您需要的连接越多(即嵌套越多),情况就会变得越来越糟
  • 有笛卡尔积。如果您想一次性完成,则不能嵌套多个集合而不在子 table 之间产生笛卡尔积。使用笛卡尔积,将很难“记住”哪些组合实际上是合法的,哪些是连接树的产物。因此,您将返回 运行 多个查询,每个嵌套树分支一个

使用标准 SQL JSON

但是,从 jOOQ 3.14 开始,有更好的方法。您可以使用 XML 或 JSON,具体取决于您使用的数据库方言。这里的关键特性是 XMLAGG and JSON_ARRAYAGG,它允许将数据聚合到 XML 元素或 JSON 对象中。由于您将使用 GraphQL 生成 JSON 文档,我猜您将使用 JSON.

使用标准 SQL(例如由 Oracle 实施),您为示例生成的 SQL 查询可能如下所示:

SELECT
  JSON_ARRAYAGG(
    JSON_OBJECT(
      KEY "id" VALUE foo.id,
      KEY "name" VALUE foo.name,
      KEY "bars" VALUE (
        SELECT 
          JSON_ARRAYAGG(
            JSON_OBJECT(
              KEY "id" VALUE bar.id,
              KEY "name" VALUE bar.name
            )
          )
        FROM bar
        WHERE bar.foo_id = foo.id
      )
    )
  )
FROM foo

就目前而言,这些方言应该能够支持 jsonArrayAgg() and jsonObject()(或其模拟,例如在 PostgreSQL 中):

  • 蟑螂数据库
  • Db2 LUW 11+
  • H2
  • MariaDB 10.2+
  • MySQL 5.7+
  • 甲骨文 12c+
  • PostgreSQL

More details in this blog post.

SQL 服务器中使用 FOR JSON 的仿真在未来也可能成为可能。

请注意,JSON_ARRAYAGG() 将空集聚合到 NULL,而不是空集 []

开箱即用的解决方案

事实上,我之前就想过要开箱即用。我们可能会在不久的将来这样做:https://github.com/jOOQ/jOOQ/issues/10122