Проблемы с разбиением на страницы SQL и, в частности, с загрузкой данных GraphQL

#postgresql #orm #pagination #graphql #dataloader

Вопрос:

Я провел некоторое исследование о том, как настроить новый проект API GraphQL, но сталкиваюсь с некоторыми базовыми концепциями? проблемы при попытке выяснить, как эффективно выполнять разбиение на страницы и вложенные запросы к базе данных.

Я был бы признателен за любые указания или советы!

Допустим, мы получаем запрос graphql примерно так:

 articles(limit: 10) {
  title
  content
  comments(limit: 5) {
    postedAt
    text
  }
}
 

Типичный ORM, предполагающий быструю загрузку вложенного типа, мог бы преобразовать этот тип запроса в sql-запрос, подобный этому, а затем выполнить цикл над результатами, чтобы вручную сгруппировать комментарии вместе и увлажнить все это.

 select a.title, a.content, c.posted_at, c.text
from articles as a
left join comments as c on c.article_id = a.id
limit ???
 

Но до сих пор я только когда-либо видел, чтобы ORM, такие как Doctrine (php) и Sequelize (js), не справлялись с правильным разбиением на страницы в этих случаях. Они не могут правильно обрабатывать размеры страниц, потому что нет способа выразить limit это в настройках этого sql-запроса.

  • => Правильно ли я вижу эту проблему? Или я упускаю что-то важное, могут ли ORMs каким-то образом выполнять разбиение на страницы с нетерпеливо загруженными данными?

Так что теперь я совсем недавно наткнулся на lateral тип соединения в Postgres, который, похоже, решает эту проблему, при условии, что мы также добавим некоторые хитрости json:

 select a.title, a.content, t.data as comments
from articles as a
join lateral (
  select json_agg(sub.*) as data
  from (
    select c.posted_at, c.text
    from comments as c
    where c.article_id = a.id
    limit 5
  ) sub
) t on true
limit 20;
 

(I think I’ve seen this kind of lateral json trickery stuff in how Hasura and Postgraphile transform to sql, so I don’t this it’s unwarranted / bad engineering.)

  • => Is there any ORM out there (except hasura/postgraphile), possibly Postgres-specific, that use this kind of lateral and json stuff, instead of the typical method described above?

Наконец, мои исследования научили меня тому, что при создании API graphql вы, как правило, обнаруживаете, что загружаете данные (пакетные) вложенные запросы, а не загружаете их из «родительского» запроса. Так, например, это было бы без загрузки данных:

 class ArticleResolver {

  comments(article) {
    db.query("select ... from comments where ... = {article.id}");
  }
 

и тогда это будет связано с загрузкой данных:

 class ArticleResolver {

  commentsDataLoader = new DataLoader(articleIds => {
    return db.query("select ... from comments where ... in {articleIds}");
  });

  comments(article) {
    return this.commentsDataLoader.load(article.id);
  }
 

Но как только вы захотите начать добавлять параметры, например limit: 5 , во вложенные запросы, этот запрос на загрузку данных станет таким же сложным, как и исходный вопрос, поэтому мы вернулись к тому, с чего начали 🙂

  • => Существует ли обычный способ, некоторые стандартные методы, для решения этой проблемы? Есть ли какой-либо известный способ / библиотека, чтобы так легко выписывать распознаватели, как, например, это:
 class ArticleResolver
  ...

  comments(article, limit) {
    return db.somehowMagicallyDataloaded("select * from comments ... = {article.id} limit {limit}")
  }
 

Комментарии:

1.github.com/graphql/dataloader ?

2. Да, вопрос в использовании загрузчиков данных 🙂