GraphQL 查询中的多项查找

Posted

技术标签:

【中文标题】GraphQL 查询中的多项查找【英文标题】:Multiple item lookup in GraphQL Query 【发布时间】:2020-01-15 23:27:02 【问题描述】:

我想知道基于 ID 查找多个项目的最常用方法是什么。根据我的天真理解,我看到了 3 个选项:

选项 1

接受 ID 数组并返回所有结果

products(ids: [ID!]!): [Product!]!

这似乎是最直接、最直观的方法,但不允许客户端对结果进行索引,并且会偏离其他查询通常遵循的分页模式。

选项 2

强制客户端使用别名

product(id: ID!): Product!

这在服务器端最容易实现,还允许客户端根据 ID 直接索引到结果中(假设他们使用 ID 作为别名),但也迫使客户端构造更复杂的查询。

选项 3

接受 ID 数组并返回分页结果(通过连接模式)

products(ids: [ID!]!, after: String, first: Int! = 10): ProductConnection!

这与返回分页结果的其他查询保持一致,但也存在与 #1 相同的问题,即不允许客户端通过 ID 直接索引到结果中(假设 ID 用作选项 2 中的别名)。对于不熟悉的用户来说,连接模式也不是很直观。

根据您的经验有什么建议吗?谢谢!

【问题讨论】:

我想你在这里涵盖了所有的方式。我想提一下,有些人鼓励为视图而不是一般查询构建的查询。此外,we 经常做的是同时设置选项 2 和选项 3,并在复数版本上提供更灵活的过滤器参数,例如products(filter: id: in: [1, 2, 3] ). 感谢@Herku 的洞察力!对于复数版本,您要返回什么?一系列产品,还是一个连接?另外,您是否使用任何库/框架进行过滤?除了in,您还公开了其他“过滤器”吗?您是否将参数命名为 ProductFilterInput 之类的名称?感谢您的帮助! 【参考方案1】:

这个答案不一定要介绍更多的做事方式,但我会详细说明我为我的架构找到的一些最佳实践,以及它们与社区项目的关系。

选项 2 不适用于静态查询

正如我在评论中已经讨论过的,想想你的应用真正需要什么。如果您想通过 ID 查找动态数量的字段 选项 2 在您想使用 static queries 时将没有帮助。您必须连接字符串才能大致像这样创建动态查询:

const query = ` $ids.map(id => `product$id: product  ...Frag \n`).join('') `;

这是一个坏主意,链接的文章讨论了为什么以及您的 GraphQL 端点可能不适合它。我们也可以为每个产品一个一个地发送多个查询,但这样我们就失去了 GraphQL 相对于 REST 的关键优势之一。

但是:我们通常保留查询单个实体的字段,因为查看单个项目通常是我们应用程序的一个用例,我们可以非常快速地响应该查询。请参阅我关于查询的答案的最后一部分。

其他两个选项基本相同

选项 1选项 3 应该在您的项目中始终如一地选择。在查询 ID 时,连接可能没有真正的帮助,但它可以防止返回到许多项目并与 Relay 无缝集成。

您还需要考虑如何再次将前端的 ID 与值连接起来。您是按照查询的顺序返回项目(例如从 Dataloader 知道的)还是查询实体的 ID 并且顺序无关紧要。

因此,如果您返回多个项目的所有查询都返回连接,那么我也会在这里执行。危险在于查询会变得复杂,这就引出了最后一个主题。

认为有害的通用过滤器

一般而言,建议仅将前端真正需要的查询公开为this Twitter thread elaborates,Lee Byron(其中一位创建者)添加了that you should also only expose queries that you can fulfill efficiently。相比之下,Apollo 建议使用not couple clients and server implementations,而不是抽象模式。我想你必须找到一个平衡点。

我认为公开一个非常具体的过滤器对象几乎与每次创建一个新字段一样好,但它可能无法很好地扩展。您将很快需要构建复杂的查询,查询构建器库可能会有所帮助。另一方面,如果您已经具备该功能 - 就像您的示例产品可能已经被高度过滤 - 它可以很容易添加。

一些野外项目提供了广泛的过滤器,如Hasura、Prisma 和Gatsby。因此,如果您想构建更通用的过滤器,您可以从这些项目中获得灵感。

【讨论】:

我很想了解更多关于这些方法的客户端缓存的后果。似乎选项 2 可能开箱即用(客户端不会重复相同的查询,而选项 1 和 3 将始终必须查询整个列表,即使 id 不同? 理论上你不必查询整个列表,但实际上可用的缓存解决方案不够聪明,无法处理这个问题。如果这被证明是您的应用程序的瓶颈,您可能需要针对这种情况的特殊解决方案。

以上是关于GraphQL 查询中的多项查找的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL 嵌套查询查找

GraphQL 中的多对多关系

GraphQL 查询在 realations 上查找相等字段

在 React 组件中的多个 GraphQL 查询之间进行更改

GraphQL Apollo 中的多对多关系

当我从 Angular 传递 graphql 查询时,为啥 GraphQL 控制器中的参数查询为空?