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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:17:49