从10月8日至10日加入我们在纽约市的 GraphQL 联邦和 API 平台工程讲座,了解最新技巧、趋势和新闻。加入2024年纽约市 GraphQL 高峰会
文档
免费开始

定义高级键

定义和使用复合键、嵌套键字段等


根据您的实体和用法,您可能需要使用更高级的@key。例如,您可能需要定义一个复合 @key如果需要多个字段来唯一标识一个。如果不同的与实体的不同字段交互,您可能需要为该实体定义多个——有时不同的——@key

复合 @key

一个单独的@key可以由多个字段组成,这些字段的组合可以唯一标识一个实体。这被称为复合键或合成键。In the following example, the combination of both username and domain fields is required to uniquely identify the User entity:

用户子图
type User @key(fields: "username domain") {
username: String!
domain: String!
}

在复合 @key 中的嵌套字段

嵌套 字段常用于复合键。以下示例中,User 实体's @key 包含了一个用户的 id 以及该用户相关的 Organizationid

用户子图
type User @key(fields: "id organization { id }") {
id: ID!
organization: Organization!
}
type Organization {
id: ID!
}

注意

虽然嵌套 字段最常用于复合键,但你也可以将其用作单个 @key

多个 @key

当不同的 子图 与实体 的不同字段交互时,你可能需要为实体定义多个 @key。例如,一个 子图可能会通过其 ID 引用产品,而一个 子图可能会使用 SKU。

以下示例中,Product 实体可以通过其 id 或其 sku 唯一识别:

产品子图
type Product @key(fields: "id") @key(fields: "sku") {
id: ID!
sku: String!
name: String!
price: Int
}

注意

如果你包含了多组 @key 字段,查询规划器会使用最高效的组来解决实体。例如,假设你允许使用以下类型来识别:

type Product @key(fields: "id") @key(fields: "id sku") {
# ...
}

这意味着 id(idsku) 就足够唯一地识别实体。由于 id 本身就足够了,查询规划器将仅使用该字段来解决实体,并且 @key(fields: "id sku") 将有效地被忽略。

使用多个键引用实体

一个子图,它是通过不提供任何字段来引用实体的,可以在这个实体的stub定义中使用任何键字段。

产品子图
type Product @key(fields: "id") @key(fields: "sku") {
id: ID!
sku: String!
name: String!
price: Int
}

例如,如果“产品”子图定义实体如Product

评论子图
# Either:
type Product @key(fields: "id", resolvable: false) {
id: ID!
}
# Or:
type Product @key(fields: "sku", resolvable: false) {
sku: String!
}

在一个具有多个键的实体引用解析时,可以根据哪些键存在来决定如何解析。例如,如果你使用,则可能如下所示:

resolvers.js
// Products subgraph
const resolvers = {
Product: {
__resolveReference(productRepresentation) {
if(productRepresentation.sku){
return fetchProductBySku(productRepresentation.sku);
} else {
return fetchProductByID(productRepresentation.id);
}
}
},
// ...other resolvers...
}

不同子图中的不同键

尽管实体在子图中通常使用完全相同的@key字段,但你可以使用具有不同字段的不同的@key。例如,你可以定义跨子图的共享实体“Product”,一个具有skuupc作为其@key字段,另一个仅具有upc作为字段:

产品子图
type Product @key(fields: "sku") @key(fields: "upc") {
sku: ID!
upc: String!
name: String!
price: Int
}
库存子图
type Product @key(fields: "upc") {
upc: String!
inStock: Boolean!
}

要合并子图之间的实体,实体必须在子图之间至少共享一个字段。例如,不能合并以下子图中的“Product”实体,因为它们没有在@key选择集中指定的任何共享字段:

产品子图
type Product @key(fields: "sku") {
sku: ID!
name: String!
price: Int
}
库存子图
type Product @key(fields: "upc") {
upc: String!
inStock: Boolean!
}

有不同键选择的操作

子图中的不同键会影响可以从每个子图中解析实体的哪些字段。如果存在从根到字段的可遍历路径,则请求可以解析字段。

以下为例:

产品子图
type Product @key(fields: "sku") {
sku: ID!
upc: String!
name: String!
price: Int
}
type Query {
product(sku: ID!): Product
products: [Product!]!
}
库存子图
type Product @key(fields: "upc") {
upc: String!
inStock: Boolean!
}

产品子图定义的查询可以始终解析所有产品字段,因为产品实体可以通过同时存在于两个模式中的 upc 字段进行联接。

另一方面,添加到库存子图的查询无法解析来自产品子图的字段:

产品子图
type Product @key(fields: "sku") {
sku: ID!
upc: String!
name: String!
price: Int
}
库存子图
type Product @key(fields: "upc") {
upc: String!
inStock: Boolean!
}
type Query {
productsInStock: [Product!]!
}

由于产品子图的 Product 类型定义不包括 upc 作为键字段,而 sku 字段在库存子图中不存在,因此 productsInStock 查询无法解析来自产品子图中的字段。

如果产品子图包含 @key(fields: "upc"),所有来自库存子图的查询都可以解析所有产品字段:

产品子图
type Product @key(fields: "sku") @key(fields: "upc") {
sku: ID!
upc: String!
name: String!
price: Int
}
库存子图
type Product @key(fields: "upc") {
upc: String!
inStock: Boolean!
}
type Query {
productsInStock: [Product!]!
}

下一步

如果您还没有学习如何 将实体字段贡献给超级图 并从未贡献任何字段的子图中 引用它们。

上一页
实体的介绍
下一页
贡献和引用实体字段
评价文章评价在GitHub上编辑编辑论坛Discord

©2024Apache Graph Inc.,商业名称Apache GraphQL。

隐私政策

公司