Это продолжение моего предыдущего блога, в котором объяснялся лучший способ разрешения полей запроса 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.