У меня есть сервер GraphQL, который может обслуживать данные таймсерий для указанного источника (например, данные датчика). Пример запроса для получения данных для датчика может быть таким:
query fetchData {
timeseriesData(sourceId: "source1") {
data {
time
value
}
}
}
В моем интерфейсе я хочу разрешить пользователю выбирать 1 или несколько источников и показывать диаграмму с линией для каждого из них. Похоже, это можно было бы сделать, используя такой запрос:
query fetchData {
series1: timeseriesData(sourceId: "source1") {
data {
time
value
}
}
series2: timeseriesData(sourceId: "source2") {
data {
time
value
}
}
}
Большинство руководств по GraphQL, похоже, сосредоточены на статических запросах (например, когда изменяется только переменная, но не фактическая форма запроса), но в моем случае мне нужно, чтобы сам запрос был динамическим (один запрос timeseriesData для каждого из мои выбранные идентификаторы).
У меня есть следующие ограничения:
Стек, который я использую:
В идеале я хочу каким-то образом объединить два запроса в один, чтобы я мог определить их в соответствии с первым примером, но затем объединить их вместе на уровне абстракции, чтобы получить один запрос, подобный второму примеру, для быть отправленным по проводам.
Однако я не уверен, как этого добиться, потому что graphql-tag анализирует запрос в AST, и я изо всех сил пытаюсь понять, возможно ли манипулировать запросом таким образом.
Какие существуют методы для создания такого динамического запроса, когда форма запроса заранее не известен?


Я думаю, вы могли бы использовать для этого фрагменты! Но вам все равно придется записать 2 "queries" в данном случае fragments.
Сначала давайте создадим fragment для каждого timeSeries, пожалуйста, проверьте свой тип запроса timeSeries, я буду называть его timeseriesDataQuery
const series1Q = gql`
fragment series1 on timeseriesDataQuery {
series1: timeseriesData(sourceId: "source1") {
data {
time
value
}
}
}
}
const series2Q = gql`
fragment series2 on timeseriesDataQuery {
series2: timeseriesData(sourceId: "source2") {
data {
time
value
}
}
}
}
А потом просто сшиваем их в запросе:
export const mainQuery = gql`
query fetchData {
...series1
...series2
}
${series1Q}
${series2Q}
`
@Evilsanta, если вы динамически определяете фрагменты и их ссылку в основном запросе, я думаю, что это возможно.
Вы можете использовать фрагмент для определения общих полей и привязанные к переменной директивы @include(if: Boolean) и @skip(if: Boolean) для этого фрагмента, чтобы получить динамические поля, которые известны во время выполнения.
Согласно спецификации, лучше избегать ручной интерполяции строк для построения динамических запросов.
Директивы 1 позволяют включать или пропускать поле на основе логического выражения, переданного как переменная запроса. Директива может быть прикреплена к полю или включению фрагмента и может повлиять на выполнение запроса любым способом, который пожелает сервер.
query Hero($episode: Episode, $withFriends: Boolean!) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}
И в переменных:
{
"episode": "JEDI",
"withFriends": false
}
Конечно, вы можете отправлять именованные запросы, как во втором примере. Клиенты будут автоматически группировать запросы.
@ Мэтт Уилсон, вы когда-нибудь придумывали решение этой проблемы? Я в такой же ситуации. У меня есть массив идентификаторов из другой службы, и для каждого мне нужно вызвать запрос graphql и попытаться вызвать их либо как 1, либо партиями
@ Mr.7 Привет, я использую Apollo и Apollo Client и обнаружил, что этот "BatchHttpLink" - это метод. Я помещаю свое решение здесь: koala-moon.com/vue-js-apollo-set-up-with-batch-query-processing И документы Apollo: apollographql.com/docs/link/links/batch-http На стороне клиента вы просто создаете новое соединение с сервером graphql (Apollo), которое ждет некоторое время перед отправкой запроса или запросов в пакете. За последние несколько месяцев он без проблем обрабатывал сотни запросов пользователей.
Спасибо @ user3067684 Я посмотрю :)
Я думаю, у вас нет выбора, кроме использования функций String, когда пользователь выбирает датчики динамически, и даже вы не знаете датчики во время разработки (не во время выполнения).
const mainQuery = gql
`query fetchData($sourceId: String!) {
timeseriesData(sourceId: $sourceId) {
data {
time
value
}
}
}`;
const mainQueryStr = mainQuery.loc.source.body;
mainQueryStr - это строковое значение вашего запроса (для обработки динамичности вашей проблемы)
Затем подключите датчики и замените $sourceId на идентификатор каждого датчика.
// You have to remove the query wrapper first
// Then replace sensor id
const sensorsQueries = sensors.map(sid => mainQueryStr
.split(`\n`)
.slice(1, 7)
.replace(`$sourceId`, sid)
)
Затем вам следует присоединиться к sensorQueries и сделать новый запрос GraphQL.
const finalQuery = gql`
query fetchData {
${sensorsQueries.join(`\n`)}`
};
В этом случае вы можете использовать такие преимущества инструментов, как автозаполнение, подсветка синтаксиса и ...
для запроса mainQuery, а не finalQuery (из-за того, что вы создаете его динамически)
Быстрый вопрос: если у меня есть несколько фрагментов, длина которых мне неизвестна, могу ли я таким образом построить mainQuery? например, динамически добавлять в запрос несколько фрагментов?