有啥方法可以将 GraphQL 查询的多个 Fragment 扩展拆分为多个调用?
Posted
技术标签:
【中文标题】有啥方法可以将 GraphQL 查询的多个 Fragment 扩展拆分为多个调用?【英文标题】:Any way to split up multiple Fragment expansions for a GraphQL query into multiple calls?有什么方法可以将 GraphQL 查询的多个 Fragment 扩展拆分为多个调用? 【发布时间】:2021-11-28 18:29:45 【问题描述】:上下文
这个问题可能取决于某些选择,其中一些是可变的,而另一些则不是。我们正在使用以下技术和框架:
Relay / React / TypeScript 内容堆栈 (CMS)问题
我正在尝试创建一个高度可定制的页面,该页面可以根据呈现给它的数据从多种 UI 组件构建(以允许使用 CMS 使用预制 UI 以不可预知的顺序构建页面)。
我的第一次尝试是为可能在数组中引用的潜在 UI 组件创建一组片段:
query CustomPageQuery
title
description
customContentConnection
edges
node
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
"""
Further fragments are added here as we add more kinds of UI
"""
在我们使用的 CMS (ContentStack) 中,此查询的复杂性已经增长到被拒绝的程度,因为它需要在单个查询中调用太多数据库。出于这个原因,我希望有一种方法可以拆分对片段的调用,这样它们就不会成为初始查询的一部分,或者是一些类似的解决方案会导致将此查询分成多个部分。
我希望 @defer
指令能为我解决这个问题,但 relay-compiler
不支持它。
有什么想法吗?
【问题讨论】:
【参考方案1】:遗憾的是,@defer
仍然不是标准,因此大多数实现都不支持它(因为您还需要服务器来支持它)。
我不确定我是否正确理解了该问题,但您可能希望更多地使用@skip
或@include
根据事物的类型仅获取您需要的片段。但它需要前端知道它想事先查询什么。
query CustomPageQuery($hero: Boolean, $tweet: Boolean, $video: Boolean)
title
description
customContentConnection
edges
node
... HeroFragment @include(if: $hero)
... TweetBlockFragment @include(if: $tweet)
... EmbeddedVideoFragment @include(if: $video)
通常,您希望能够区分类型而无需进行数据库查询。所以说:
type Hero
id: ID
name: String
type Tweet
id: ID
content: String
union Content = Hero | Tweet
Content:
__resolveType: (parent, ctx) =>
// That should be able to resolve the type without a DB query
,
一旦通过,每个片段都会被解析,从而进行更多的数据库查询。如果这些没有与数据加载器正确批处理,那么您将遇到 N+1 问题。我不确定您在后端有多少控制(如果有的话),但您的问题没有灵丹妙药。
如果您无法对后端进行优化,那么我建议您尝试限制连接。他们似乎在使用基于游标的分页,因此您从 first: 10
开始,一旦返回第一批,您可以通过将 after
设置为上一批的最后一个游标来查询下一个元素:
query CustomPageQuery($after: String)
customContentConnection(first: 10, after: $after)
edges
cursor
node
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
pageInfo
hasNextPage
作为最后的手段,您可以尝试首先获取所有 ID,然后针对每个 ID(我猜使用别名)或类型(如果您可以在连接字段上过滤)对 CMS 进行后续查询。但我觉得写它很脏,所以如果可以的话,请避免它。
one: node(id: "UUID1")
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
two: node(id: "UUID2")
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
【讨论】:
嗯,这里有很好的信息。我不确定这是否真的有助于我的情况,但我很感激!我会进一步挖掘。以上是关于有啥方法可以将 GraphQL 查询的多个 Fragment 扩展拆分为多个调用?的主要内容,如果未能解决你的问题,请参考以下文章