【问题标题】:GraphQL: non-nullable subfield causes "Cannot return null for non-nullable field" errorGraphQL:不可为空的子字段导致“无法为不可为空的字段返回空值”错误
【发布时间】:2023-02-18 18:33:08
【问题描述】:

我有三个type-graphql对象(和typeorm实体):Entry(字典词条)、Meaning(词条的含义)和Pronunciation(词条的转录)。

EntryMeaning 之间是多对多关系,EntryPronunciation 之间是一对多关系。

我有 GraphQL 查询 searchEntries,它接受查询并返回匹配的 Entry 对象以及链接的 MeaningPronunciation 对象。

在我的Entry.ts 文件中,我这样定义Entry 的关系(@Field() 来自type-graphql):

  @Field(() => [Pronunciation], { nullable: "itemsAndList" })
  @OneToMany(() => Pronunciation, (pronunciation) => pronunciation.entry, {
    nullable: true,
  })
  pronunciations: Relation<Pronunciation[]> | undefined;

  @Field(() => [Meaning], { nullable: "itemsAndList" })
  @ManyToMany(() => Meaning, (meaning) => meaning.entries, { nullable: true })
  meanings: Relation<Meaning[]> | undefined;

因此,如您所见,GraphQL 应该知道 Entry 的字段 pronunciationsmeanings 可以为空。

但是,我收到此错误(来自graphql):

Cannot return null for non-nullable field Pronunciation.id.

我注意到 pronunciationsmeanings 的子元素仍然不可为空:

为什么 GraphQL 不推断如果父元素可以为空,那么它的子元素也可以为空?

附加信息:我正在使用 typeorm 的原始 SQL 查询获取数据,打印结果如下所示:

[
  {
    id: 86,
    headword: 'lightning',
    createdAt: 2023-02-17T07:12:27.825Z,
    updatedAt: 2023-02-17T07:12:27.825Z,
    meanings: [ [Object], [Object], [Object] ],
    pronunciations: [ [Object], [Object], [Object] ]
  }
]

(我使用 JSON_AGG(JSON_BUILD_OBJECT()) 来表示意义和发音的数组,并使用左连接来连接表格。)

任何帮助将不胜感激!

【问题讨论】:

  • 更新:问题出在我使用 JSON_BUILD_OBJECT() 的原始 SQL 查询中,它返回如下字段:[{ id: null, transcription: null, notes: null, userId: null },...] 而不是返回空对象。寻找解决方法
  • 查询 Pronunciationid 返回 null;在您的架构中指定的位置不能。
  • 您已发现问题 :) 发布您自己问题的答案 :)

标签: typescript postgresql graphql typeorm typegraphql


【解决方案1】:

问题不在 GraphQL 中,而是在 PostgreSQL 的 JSON_BUILD_OBJECT()(我在原始 SQL 查询中使用过)中。 (真的,这是一个关于 PostgreSQL 的问题——我会把它添加到问题标题中。)

当与 LEFT JOIN 一起使用时,JSON_BUILD_OBJECT() 返回一个像这样的对象 { id: null, transcription: null, notes: null, userId: null }JSON_AGG() 生成这些对象的数组,GraphQL 认为 meaningspronunciations 存在,在尝试访问这些 null 字段时抛出错误。

所以我们需要修改查询。真正帮助我的是 Mike Stankavich 的this answer。使用 COALESCEFILTER,新聚合如下所示:

SELECT e.*,
  COALESCE(
    JSON_AGG(m.*)
    FILTER (WHERE m.id IS NOT NULL),
    '[]'
  ) meanings,
  COALESCE(
    JSON_AGG(p.*)
    FILTER (WHERE p.id IS NOT NULL),
    '[]'
  ) pronunciations
...

COALESCE 返回第一个不为空的参数,因此它是 JSON 数组或 []。对于构建 JSON 数组的 JSON_AGG()FILTER,正如 Mike 所写,“阻止聚合处理空行,因为不满足左连接条件,所以你最终得到一个数据库空而不是json [空]。”

具有 meanings 但没有 pronunciations 的条目的 GraphQL 响应看起来像这样:

searchEntries": [
  {
    "id": 86,
    "headword": "shwepsi",
    "pronunciations": [],
    "meanings": [
      {
        "id": 59,
        "definition": " arg"
      },
      ...]
  }

【讨论】:

    猜你喜欢
    • 2021-03-18
    • 2021-11-27
    • 2021-10-24
    • 2021-12-09
    • 2021-10-29
    • 2019-05-28
    • 2022-01-02
    • 2019-10-25
    • 2019-07-08
    相关资源
    最近更新 更多