Как улучшить производительность вложенных соединений GraphQL при использовании пагинации - PullRequest
2 голосов
/ 16 февраля 2020

Я пытаюсь реализовать какой-то базовый проект социальной сети c. Он имеет Posts, Comments и Likes, как и любой другой.

  • У поста может быть много комментариев
  • У поста может быть много лайков
  • Сообщение может иметь одного автора

У меня есть /posts маршрут в клиентском приложении. Он перечисляет Posts по страницам и показывает их title, image, authorName, commentCount и likesCount.

Запрос graphql такой:

query {
  posts(first: 10, after: "123456") {
    totalCount
    edges {
      node {
        id
        title
        imageUrl
        author {
          id
          username
        }
        comments {
          totalCount
        }
        likes {
          totalCount
        }
      }
    }
  }
}

Я использую apollo-server, TypeORM, PostgreSQL и dataloader. Я использую dataloader, чтобы получить author каждого сообщения. Я просто пакетирую запрошенный authorIds с помощью dataloader, получаю authors из PostgreSQL с помощью запроса where user.id in authorIds, сопоставляю результат запроса каждому authorId. Вы знаете, самый основной c тип использования dataloader.

Но когда я пытаюсь запросить соединение comments или likes под каждым post, я застреваю. Я мог бы использовать ту же технику и использовать для них postId, если не было нумерации страниц. Но теперь я должен включить параметры фильтра для нумерации страниц. И, возможно, есть другие параметры фильтра для некоторых условий where.

Я нашел опцию cacheKeyFn загрузчика данных. Я просто создаю строковый ключ для переданного объекта фильтра в загрузчик данных, и он не дублирует их. Он просто передает уникальные на batchFn. Но я не могу создать запрос sql с TypeORM, чтобы получить результаты для каждого аргумента first, after, orderBy отдельно и отобразить результаты обратно в функцию, которая вызвала загрузчик данных.

Я искал исходный код spectrum.chat и думаю, что они не позволяют пользователям запрашивать вложенные соединения. Также пробовал Github GraphQL Explorer, и он позволяет запрашивать вложенные соединения.

Есть ли какой-нибудь рекомендуемый способ добиться этого? Я понял, как передать object в dataloader и пакетировать их, используя cacheKeyFn, но не могу понять, как получить результаты из PostgreSQL в одном запросе и отобразить результаты для возврата из загрузчика.

Спасибо!

1 Ответ

0 голосов
/ 16 февраля 2020

Итак, если вы немного ограничиваете это, это выполнимо. Ограничение состоит в том, чтобы разрешать только пакетные соединения на первой странице результатов, например, чтобы все соединения, которые вы выбираете параллельно, выполнялись с параметрами. Это разумное ограничение, поскольку оно позволяет вам делать такие вещи, как получение первых 10 элементов фида и первых 3 комментариев для каждого из них, что представляет собой довольно типичный вариант использования. Попытка поддержать независимую нумерацию страниц в одном запросе вряд ли будет соответствовать каким-либо реальным сценариям использования пользовательского интерфейса, так что это, вероятно, чрезмерная оптимизация. Имея это в виду, вы можете поддержать вариант использования «для каждого родителя получите первых N детей», используя PostgreSQL using window.

Это немного сложно, но есть ответы, которые помогут вам в этом. правильное направление: Сгруппированный LIMIT в PostgreSQL: показать первые N строк для каждой группы?

Так что используйте dateloader, как у вас с cacheKeyFn, и пусть ваша функция загрузчика распознает, Вы можете выполнить оптимизацию (например, после is null и все остальные аргументы такие же). Если вы можете оптимизировать, используйте оконный запрос, в противном случае выполняйте неоптимизированные запросы параллельно, как обычно.

...