You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Amplify使用@queryField查询排序列表报错问题求助

问题描述

这是此前「从AWS拉取的元素无法正确排序」问题的后续跟进。
在采纳相关建议后,我生成了listSortedAlbumCategories查询的对应代码,如下所示:

export const listSortedAlbumCategories = /* GraphQL */ `
  query ListSortedAlbumCategories(
    $id: ID
    $sortOrder: ModelIntKeyConditionInput
    $sortDirection: ModelSortDirection
    $filter: ModelAlbumCategoryFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listSortedAlbumCategories(
      id: $id
      sortOrder: $sortOrder
      sortDirection: $sortDirection
      filter: $filter
      limit: $limit
      nextToken: $nextToken
    ) {
      items {
        id
        title
        sortOrder
        albums {
          nextToken
        }
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`

随后更新业务代码调用该查询:

useEffect( () => {

    const fetchAlbumCategories = async() => {
      try {
        const data = await API.graphql(graphqlOperation(listSortedAlbumCategories));
        setCategories(data.data.listSortedAlbumCategories.items);
      } catch (e) {
        console.log(e);
      }
    }

    console.log("Fetching album categories...")
    fetchAlbumCategories();
  },[]);

调用接口时返回如下错误信息:

{
  "data": null,
  "errors": [
    {
      "locations": [
        {
          "column": 15,
          "line": 1,
          "sourceName": null
        }
      ],
      "message": "Variable 'id' has coerced Null value for NonNull type 'ID!'",
      "path": null
    }
  ]
}

{
  "data": {
    "listSortedAlbumCategories": null
  },
  "errors": [
    {
      "data": null,
      "errorInfo": null,
      "errorType": "MappingTemplate",
      "locations": [
        {
          "column": 3,
          "line": 2,
          "sourceName": null
        }
      ],
      "message": "Expression block '$[query]' requires an expression",
      "path": [
        "listSortedAlbumCategories"
      ]
    }
  ]
}

该查询和原生listAlbumCategorys查询结构高度相似,仅新增了sortOrder相关参数,暂时无法定位问题。

问题排查与解决方案

两个报错的根因一致:你创建的listSortedAlbumCategories是基于DynamoDB二级索引(GSI)的查询,不是原生的全表列表查询,这类查询强制要求传入分区键(HASH键)的值。你在前端调用时没有传任何参数,id作为该GSI的分区键在后端Schema中被定义为非空ID!类型,传空值直接触发第一个参数校验错误;后续AppSync的VTL映射模板拿不到分区键值,无法拼接合法的查询表达式,就触发了第二个映射模板错误。

原生listAlbumCategorys是全表Scan类查询,不需要指定分区键,和自定义GSI查询的底层逻辑完全不同,不能直接照搬无参调用的写法。

按以下步骤修复即可:

  • 先核对GSI的键配置:如果建这个GSI的目的是拉取全量相册分类并按sortOrder排序,当前用id作为分区键的设计是错误的——id是每条分类记录的唯一标识,用它当分区键的话,每次查询必须传入具体的分类ID,只能查到单条数据,根本无法实现全量列表排序。正确的设计是用一个所有分类记录取值固定的公共字段作为分区键(比如新增categoryType字段,所有分类记录的该字段值统一设为albumCategory),把sortOrder设为排序键(RANGE键)。
  • 如果已经是「固定值分区键+sortOrder排序键」的正确GSI结构,修改GraphQL查询定义,将分区键参数标记为非空,调用时传入固定的分区键值即可。
    以分区键为categoryType举例,修改后的查询代码:
    export const listSortedAlbumCategories = /* GraphQL */ `
      query ListSortedAlbumCategories(
        $categoryType: String! # 对应GSI分区键,标记为非空
        $sortDirection: ModelSortDirection
        $filter: ModelAlbumCategoryFilterInput
        $limit: Int
        $nextToken: String
      ) {
        listSortedAlbumCategories(
          categoryType: $categoryType
          sortDirection: $sortDirection
          filter: $filter
          limit: $limit
          nextToken: $nextToken
        ) {
          items {
            id
            title
            sortOrder
            albums {
              nextToken
            }
            createdAt
            updatedAt
          }
          nextToken
        }
      }
    `
    
    调用时传入对应参数:
    const data = await API.graphql(graphqlOperation(listSortedAlbumCategories, {
      categoryType: 'albumCategory', // 和所有分类记录上的分区键值保持一致
      sortDirection: 'ASC' // 按sortOrder升序排列,需要降序则传'DESC'
    }));
    
  • 如果当前GSI确实错误地把id设为了分区键,先去Amplify后台修改数据模型的索引配置,执行amplify push完成云端部署后,再按上述逻辑调整查询和调用代码即可。

注意:不要试图通过把$id参数标记为可空类型绕过校验,AppSync的GSI查询规则强制要求分区键不能为null,即便查询定义里标为可空,传null值依然会触发报错。

内容的提问来源于stack exchange,提问作者swsoft

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:57:34