#optimization #graphql #normalization
Вопрос:
Учитывая, что «у пользователя много ссылок» (что означает, что ссылка была создана пользователем), я хочу разработать API для извлечения ссылок вместе с пользователями, чтобы возвращаемые данные не содержали дублированных пользователей.
Другими словами, вместо этого запроса:
query {
links {
id
user {
id email
}
}
}
это возвращает следующие данные:
{
"data": {
"links": [
{
"id": 1,
"user": {
"id": 2,
"email": "user2@example.com"
}
},
{
"id": 2,
"user": {
"id": 2,
"email": "user2@example.com"
}
}
]
}
}
Я хочу сделать такой запрос (обратите внимание на колонку «ссылки»):
query {
links {
id
userId
}
references {
users {
id
email
}
}
}
это возвращает связанных пользователей без дубликатов:
{
"data": {
"links": [
{
"id": 1,
"userId": 2
},
{
"id": 2,
"userId": 2
},
],
"references": {
"users": [
{
"id": 2,
"email": "user2@example.com"
}
]
}
}
}
Это должно уменьшить объем данных, передаваемых между клиентом и сервером, что немного повышает скорость.
Существует ли готовая общая реализация этой идеи на любом языке? (В идеале, в поисках Руби)
Ответ №1:
Это не запрос или роль сервера для нормализации данных.
- в спецификациях GraphQL таких возможностей нет;
- сервер должен возвращать все запрошенные поля в структуре запрошенного [ответа] ;
… но вы можете реализовать некоторые:
- стандартная (обычно используемая) разбивка на страницы (стиль ретрансляции
edges
/nodes
,nodes
только или лучше и то, и другое); - веса запросов [сложности] для продвижения этого оптимизированного стиля запросов — отдельная проблема;
- поле справочного словаря в пределах запрашиваемого типа;
links {
egdes {
node {
id
title
url
authorId
# possible but limited usage with heavy weights
# author {
# id
# email
# }
}
}
pageInfo {
hasNextPages
}
referencedUsers {
id
email
}
}
где:
User
имеетid
иemail
реквизит;referencedUsers
это[User!]
тип;node.author
этоUser
тип;
Нормализующий клиент Graphql, например Apollo
, может легко получить доступ к кэшированным пользовательским полям, не делая отдельных запросов.
Вы можете визуализировать (реагировать?) некоторый <User/>
компонент (внутри <Link />
компонента), передаваемый node.authorId
в качестве аргумента, например <User id={authorId} />
. Пользовательский компонент может useQuery
подключаться к cache-only
политике для чтения реквизитов/полей пользователя.
Подробности см. в документах Apollo. Вы должны реализовать это для себя и документировать это, чтобы помочь/направлять пользователей API.
Комментарии:
1. Спасибо! Да, я знаю, что в Apollo есть система кэширования, которая не будет запрашивать данные из бэкэнда, если они уже получены с помощью ключа
Type#id
. Это, конечно, приятно. Но вопрос больше связан с уменьшением трафика данных между сервером и клиентом.2. И как реализовать этот хитрый распознаватель, который позволил бы выбирать объекты, на которые ссылаются, в отдельной структуре.
3. [вероятно] вы не уменьшите трафик без взвешенных запросов … ИДК руби … в общем случае [поток разрешения graphql] это может быть похоже …
links
распознаватель считывает записи из одной таблицы БД, просто собирает идентификаторы пользователей в некоторый массив (сохраняетlinks
объект результата рядом с ребрами/узлами и информацией о разбивке на страницы), использует его вreferencedUsers
распознавателе (поparent
1-му аргументу) для извлечения пользователей из 2-й таблицы БД