DynamoDB+AppSync多属性查询单nextToken分页实现方案咨询
优化方案
核心思路是修改userIndex的排序键为复合字段,利用DynamoDB排序键的前缀匹配排序能力,直接实现通知按状态优先级+时间的排序规则,无需额外过滤,一次查询即可满足需求。
1. 调整GSI结构
原有userIndex的排序键仅为timestamp,无法实现状态优先级排序,我们将排序键替换为复合字段status_sort_key,调整后的GSI规则如下:
- GSI分区键:保持原有用户ID字段(用于过滤单用户通知)
- GSI排序键:新增
status_sort_key字段,存储规则为:- 待处理(pending)通知前缀拼接
0#,格式为0#${13位毫秒时间戳} - 非待处理(default)通知前缀拼接
1#,格式为1#${13位毫秒时间戳}
- 待处理(pending)通知前缀拼接
因为字符串排序特性,0#开头的所有记录会排在1#开头的记录之前,同一前缀下的13位时间戳字符串排序和数字排序逻辑完全一致,自动实现同状态按时间排序的需求。
如果你的项目使用Amplify GraphQL的@model/@index(旧版为@key)装饰器,可直接参考如下Schema定义:
# 先定义状态枚举,避免非法值 enum NotificationStatus { PENDING DEFAULT } type Notification @model { notification_id: ID! # 定义userIndex,分区键为user_id,排序键为status_sort_key user_id: ID! @index( name: "userIndex" sortKeyFields: ["status_sort_key"] queryField: "listNotificationsByUser" ) content: String! status: NotificationStatus! timestamp: Int! status_sort_key: String! }
2. 数据写入逻辑调整
新增/更新通知状态时,自动生成status_sort_key的值即可,不需要修改其他原有逻辑:
- 若状态为pending:
status_sort_key = "0#" + timestamp - 若状态为default:
status_sort_key = "1#" + timestamp
如果需要同状态下最新通知排在前面,可将时间戳取反后拼接(或查询时指定排序方向为降序,同时把pending的前缀改为2#、default改为1#,保证降序时pending在前)。
3. 查询逻辑改造
现在仅需要发起一次查询,调用对应userIndex的查询接口,指定分区键为当前用户ID,排序方向为升序即可直接返回符合排序要求的通知列表:
- 无需添加过滤表达式,所有返回结果均为有效数据,不会浪费DynamoDB读容量单位(RCU)
- 仅需要存储和传递DynamoDB返回的单个
nextToken即可完成分页,无需分别维护两类状态的分页令牌
原有方案的问题说明
之前使用过滤表达式分两次查询的方案,DynamoDB会先读取用户的所有通知,再过滤掉不符合状态条件的记录,实际消耗的RCU和读取全量用户通知一致,数据量越大浪费越严重,优化后的方案完全规避了该问题。
内容的提问来源于stack exchange,提问作者Eric Jubber
相关产品推荐
相关产品推荐

