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
相关产品推荐
相关产品推荐

