Это продолжение моего предыдущего блога, в котором объяснялся лучший способ разрешения полей запроса GraphQL. В конце этого блога появилась заметка о проблеме с запросом N + 1, возникшей при разрешении полей.

В этом сообщении блога мы увидим, как решить эту проблему запроса N + 1 с помощью Dataloader.

Что такое Dataloader?

Dataloader - это библиотека, которая обрабатывает последовательные запросы и делает один запрос данных внутри себя. Этот запрос может быть сделан к любому источнику данных, например к базе данных или веб-службе.

Dataloader принимает массив в качестве аргумента, обрабатывает данные, используя этот аргумент, и возвращает массив объектов.

Элемент с n-м индексом возвращенного массива будет рассматриваться загрузчиком данных как данные для n-го элемента во входном аргументе.

Давайте сейчас реализуем postsLoader.

Теперь мы будем использовать этот загрузчик сообщений для обработки сообщений. Обновленный resolvers будет выглядеть следующим образом:

Когда клиент запрашивает пользователей вместе с полями сообщений, то для каждого пользователя, разрешенного в запросе users, этот преобразователь сообщений будет вызываться с родительским аргументом, равным объекту пользователя. Используя этого пользователя, мы можем найти сообщения.

Как видно из преобразователя поля `posts`, мы все еще запрашиваем отдельную запись, используя API загрузчика данных` load`.

Несколько вызовов postsLoader.load () будут объединены в пакет, а затем будет вызываться `postsLoader` только один раз.

Вот скриншот, показывающий, что запросы к БД выполняются, когда клиент запрашивает данные пользователей вместе с данными их сообщений.

Однако есть одна оговорка с этой реализацией загрузчика данных.

Dataloader не только пакетирует запросы, но и кэширует ответы. Он выполняет кеширование, чтобы гарантировать, что другой запрос не будет сделан для получения тех же данных.

Проблема с этим кешированием заключается в том, что если преобразователь другого запроса также попадает в этот загрузчик данных (при обработке первого запроса), то кешированный результат также будет возвращен второму запросу. Как видите, возврат кэшированных данных в совершенно другой запрос - серьезная проблема.

Следовательно, загрузчик данных всегда должен определяться для каждого запроса.

Таким образом, разные экземпляры загрузчика данных будут использоваться разными запросами. Лучше всего определить их в контексте запроса GraphQL.

Таким образом, новая реализация загрузчика данных будет следующей:

Надеюсь, это было полезно. Обратите внимание на это репо, в котором реализован вышеупомянутый преобразователь users с использованием сервера Apollo GraphQL.