AWS AppSync分页查询nextToken返回重复数据问题排查
问题描述
我在AppSync中定义了如下GraphQL查询:
export const carsByUserGroupToCarsTable = /* GraphQL */ `query CarsByUserGroup($userGroup: String!, $limit: Int, $nextToken: String) { carsByUserGroup(userGroup: $userGroup, limit: $limit, nextToken: $nextToken) { items { vin __typename } nextToken __typename } } ` as GeneratedQuery< APITypes.CarsByUserGroupQueryVariables, APITypes.CarsByUserGroupQuery >;
调用该查询的前端函数如下:
export const fetchCarsByGroup = async (userGroup: string, limit: int, nextToken: string | null | undefined) => { console.log(JSON.stringify(nextToken)); try { const data = await client.graphql({ query: customQueries.carsByUserGroupToCarsTable, variables: { userGroup, limit: 1, //hardcoded to 1 for test purposes nextToken }, }) return data; } catch (error) { console.error('Error fetching cars:', error); } };
获取初始数据后,我把返回的nextToken存储到前端变量中,用户点击“下一页”按钮时会传入该nextToken发起新请求,且已确认nextToken已正确传递到fetchCarsByGroup函数。但新请求仍返回与初始请求相同的数据,响应中的nextToken也一致。
当前的resolver请求模板如下:
{ "version": "2017-02-28", "operation": "Query", "index": "userGroup-index", "query": { "expression": "#userGroup = :userGroup", "expressionNames": { "#userGroup": "userGroup" }, "expressionValues": { ":userGroup": { "S": "$ctx.args.userGroup" } } }, "limit": $util.defaultIfNull($ctx.args.limit, 10) }
响应模板为:
$util.toJson($ctx.result)
尝试在resolver请求模板的limit行后添加如下代码时:
"nextToken":$util.defaultIfNullOrBlank($ctx.args.nextToken, null)
触发了MappingTemplate错误:“Unable to parse the JSON document”。
推测问题出在resolver的配置上,请问如何正确传递nextToken以实现分页查询获取新数据?
解决方案
1. 修复请求模板的JSON语法错误
添加nextToken时出现解析错误,是两个原因导致的:
- 前一行
"limit": $util.defaultIfNull($ctx.args.limit, 10)末尾缺少逗号,破坏了JSON结构 $util.defaultIfNullOrBlank返回null时,直接写入JSON会导致语法错误(JSON要求null必须小写,而模板输出的可能是未转义的null值)
修正后的请求模板:
{ "version": "2017-02-28", "operation": "Query", "index": "userGroup-index", "query": { "expression": "#userGroup = :userGroup", "expressionNames": { "#userGroup": "userGroup" }, "expressionValues": { ":userGroup": { "S": "$ctx.args.userGroup" } } }, "limit": $util.defaultIfNull($ctx.args.limit, 10), "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null)) }
2. 确保DynamoDB索引包含排序键
分页失效的核心原因大概率是你的userGroup-index只有分区键(userGroup),没有排序键。DynamoDB的Query分页依赖排序键来确定分页位置,仅靠分区键无法保证同组数据的顺序一致性,导致每次请求都返回相同的前N条数据。
解决步骤:
- 给DynamoDB表的
userGroup-index添加一个排序键,比如vin(唯一)或createdAt(时间顺序)等具有唯一性或顺序性的字段 - 如果需要按特定顺序分页,可以在请求模板中添加
scanIndexForward参数控制升序/降序,例如:"scanIndexForward": true
3. 验证前端nextToken的传递格式
确认前端传递的nextToken是AppSync返回的原始字符串,没有被额外序列化或修改。DynamoDB的nextToken是经过编码的字符串,直接传递即可,无需处理。
内容的提问来源于stack exchange,提问作者Gustav Vingtoft
相关产品推荐
相关产品推荐

