(更新了更多解释)
在 GraphQL 中有 3 种方式来表示数据数组:
- 列表:当您有一个有限的关联对象列表时使用,您可以一次很好地获取所有对象。在 GraphQL SDL 中,这表示为
[Ship]
.
- 节点:当您需要对列表进行分页时使用,通常是因为可能有数千个项目。请注意,这不是 Relay 规范的一部分,因此 Relay 客户端不支持(相反,您可以将项目包装在边缘中,如 #3 中所述),但其他一些客户端(例如 Apollo)更灵活,并且支持这种结构(但您需要提供更多样板文件)。在 GraphQL 中,这将表示为
type ShipConnection { nodes: [Ship], pageInfo: PageInfo! }
.
- 边缘:除了分页之外,您还需要为连接中的每个边缘提供额外信息时使用(阅读下文了解更多详细信息)。在 GraphQL 中,您可以将其编写为
type ShipConnection { edges: [ShipEdge], pageInfo: PageInfo! }
.
请注意,您的 GraphQL 服务器可能支持特定关联的所有三个选项,然后客户端选择他们想要的字段。以下是它们的外观:
type Query {
ships: [Ship] // #1
shipsConnection: [ShipConnection]
}
type ShipConnection {
nodes: [Ship] // #2
edges: [ShipEdge] // #3
pageInfo: PageInfo!
}
type PageInfo {
endCursor // page-based pagination
hasNextPage
}
type ShipEdge {
cursor: String! // edge-based pagination
node: Ship
// ... edge attributes
}
type Ship {
// ... ship attributes
}
仅当您知道项目的数量不会增加时才应该使用列表(#1)(例如,如果您有一个Post
,您可能希望tags
作为一个列表返回,但您不应该这样做comments
)。要在 #2 和 #3 之间做出决定,仅在普通节点上使用边有两个原因:
它是边缘特定属性的地方。例如,如果您有一个User
属于许多Group
s 的 a,那么在关系数据库中您将有一个带有user_id
and的 UserGroup 表group_id
。该表可以具有其他属性role
,例如joined_at
等。GroupUserEdge
然后您可以访问这些属性的位置。
为光标留一个位置。Relay,除了基于页面的分页(使用pageInfo
)支持基于边缘的分页。为什么 Relay 每个边都需要一个光标?由于 Relay 智能地合并了来自整个应用程序的数据需求,它可能已经与您请求的相同参数建立了连接,但其中没有足够的记录。为了获取丢失的数据,它可以在某个边缘的光标之后请求连接中的数据。
我知道这可能会让人感到困惑,因为数据库也有游标,而且每个查询只有一个游标。中继连接实际上并不是一个查询,而是一组标识查询的参数。连接边缘的光标是一组参数,用于标识连接中的位置。这是比纯查询游标更高的抽象级别(请记住,即使在可能不是数据库查询或被第 3 方系统隐藏的连接上,边缘也需要能够识别位置)。由于需要灵活性,一个连接的光标是不够的。