使用 GraphQL 检索包含具有不同模式的对象数组的对象

Chr*_*son 8 contentful graphql graphql-js gatsby

我正在尝试编写一个查询来检索一个对象,该对象的属性linkedCards包含具有不同模式的对象数组。

我有 3 种不同的模式(内置Contentful):

CardA 示例:

{
    id: 42,
    productName: 'Laptop',
    price: 999
}
Run Code Online (Sandbox Code Playgroud)

CardB 示例:

{
    id: 999,
    title: 'Buy our refurbished Laptops today!'
}
Run Code Online (Sandbox Code Playgroud)

CardC 示例:

{
    id: 100,
    linkedCards: [
        {
            id: 42,
            productName: 'Laptop',
            price: 999
        },
        {
            id: 999,
            title: 'Buy our refurbished Laptops today!'
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

询问:

allCardC() {
    nodes {
        linkedCards {
            id
            title
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试运行以下 GraphQL 查询时,我得到 "Cannot query field "title" on type "CardACardBUnion". Did you mean to use an inline fragment on "CardA" or "CardB"?"

有没有内置的方法可以做到这一点,或者我可以以某种方式使用CardA&的 ID CardB?也许有一个查询来获取卡片的 idlinkedCards和另一个查询来获取所述卡片?

Dan*_*den 18

如错误所示,在查询解析为联合的字段时,您需要使用内联片段

allCardC {
    nodes {
        linkedCards {
            ... on CardA {
              id
              productName
              price
            }
            ... on CardB {
              id
              title
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以在选择集中内联定义片段。这样做是为了根据运行时类型有条件地包含字段。

与接口或常规对象类型不同,联合不指定任何特定字段,仅指定组成联合的类型。这意味着返回联合的字段的选择集必须始终使用片段根据字段解析为的实际类型有条件地指定字段。

这就像说,“如果这是返回对象的实际类型,请请求这些字段”。


Dav*_*aze 6

您可能会发现使用 GraphQL接口来指定每种卡片类型共有的字段很有用。

interface Card {
  id: ID!
}
# type CardA implements Card { ... }
type CardB implements Card {
  id: ID!
  title: String!
}
type CardC implements Card {
  id: ID!
  linkedCards: [Card!]!
}
Run Code Online (Sandbox Code Playgroud)

正如@DanielRearden 的回答所暗示的那样,您仍然需要使用(内联)片段来选择特定于其中一种卡片类型的id字段,但是现在您知道每张卡片都有一个字段,您可以直接选择该字段。

allCardC {
    nodes {
        linkedCards {
            id
            ... on CardB { title }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)