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
我正在构建 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