GraphQL Java: группировка SQL и отображение - PullRequest
1 голос
/ 24 апреля 2020

Я строю graphql- java приложение для весенней загрузки. Допустим, у меня есть эта схема:

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;

У вас есть идеи, как этого добиться? Я настоящий новичок ie в GraphQL.

Технический стек: Spring Boot JOOQ graphql- java graphql- java -tools

1 Ответ

1 голос
/ 25 апреля 2020

Classi c SQL стратегии для вложения коллекций

В вашем простом примере, LEFT JOIN, безусловно, вариант. Это то, что ORM, такие как JPA / Hibernate, делают также негласно, когда они выбирают вложенные коллекции. Стратегия имеет ряд недостатков:

  • Есть дублирование данных. Для каждого BAR (дочерняя таблица) вы будете дублировать данные соответствующего FOO (родительская таблица). Это может привести к большим накладным расходам на передачу по проводам. Это становится все хуже и хуже, чем больше соединений (т.е. больше вложений) вам требуется
  • Есть декартовы произведения. Вы не можете вкладывать более одной коллекции, не производя декартовы произведения между дочерними таблицами, если вы хотите сделать это за один go. С декартовым произведением будет трудно «запомнить», какие комбинации на самом деле являются законными, а какие являются артефактами вашего дерева соединений. Итак, вы вернетесь к выполнению нескольких запросов, по одному для каждой ветви дерева вложений

Использование стандартного SQL JSON

Но вот, есть лучший способ, начиная из jOOQ 3.14. Вы можете использовать XML или JSON, в зависимости от используемого вами диалекта базы данных. Ключевыми функциями здесь являются XMLAGG и JSON_ARRAYAGG, которые позволяют объединять данные в элемент XML или объект JSON. Поскольку вы собираетесь создавать JSON документы с GraphQL, я думаю, вы будете использовать 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() и jsonObject() (или его эмуляция, например, в PostgreSQL):

  • CockroachDB
  • Db2 LUW 11 +
  • H2
  • MariaDB 10.2 +
  • MySQL 5.7 +
  • Oracle 12c +
  • PostgreSQL

Эмуляция в SQL Сервер с использованием FOR JSON может быть возможно и в будущем.

Решение «из коробки»

На самом деле, мне приходило в голову раньше, чтобы обеспечить это из коробка. Мы могли бы сделать это в ближайшее время: https://github.com/jOOQ/jOOQ/issues/10122

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...