DynamoDB间接多对多关系设计:如何单查询判断用户是否持有指定内容
可行方案(完全符合你的约束条件)
方案1:低侵入改造,无需调整现有表结构
你原本需要两次查询的逻辑可以直接合并为单次DynamoDB API调用实现,不需要修改任何现有数据结构,也不会引入冗余一致性问题:
将两次查询逻辑封装为一个TransactGetItems请求,单次调用即可同时返回两类验证结果:
- 第一组请求:判断是否存在
PK=USER#<用户ID>、SK=CONTENT#<目标内容ID>的直接持有条目 - 第二组请求:批量查询该用户持有的所有集合下,是否存在
SK=CONTENT#<目标内容ID>的条目(如果用户持有的集合数较多,可以将用户持有的集合ID列表缓存在内存/Redis中,缓存过期时才更新,进一步降低查询开销)
只要任意一组请求返回非空结果,即可判定用户持有该内容。
该方案完全避开你提到的两个限制:没有新增任何冗余数据,集合修改时不需要同步更新其他条目,也不需要预展开集合内的所有内容。
方案2:表结构优化,纯数据库端单次查询
如果希望完全不依赖外部缓存,仅靠DynamoDB单次Query就能拿到结果,可以调整单表设计如下:
- 基础主键设计(PK为分区键,SK为排序键),新增通用属性
access_key:- 用户直接持有内容:
PK=USER#<用户ID>,SK=CONTENT#<内容ID>,access_key=ACCESS#<用户ID>#<内容ID> - 用户持有集合:
PK=USER#<用户ID>,SK=COLLECTION#<集合ID>,access_key=ACCESS#<用户ID>#* - 集合包含内容:
PK=COLLECTION#<集合ID>,SK=CONTENT#<内容ID>,access_key=ACCESS#*#<内容ID>
- 用户直接持有内容:
- 新建全局二级索引(GSI),分区键设为
access_key,排序键设为SK
查询时只需对该GSI发起一次Query,设置分区键条件为access_key IN ('ACCESS#<用户ID>#<内容ID>', 'ACCESS#<用户ID>#*', 'ACCESS#*#<内容ID>'),拿到返回结果后只需验证是否存在「用户持有的集合ID」和「包含目标内容的集合ID」的交集即可,不需要额外调用数据库。
该方案额外写入成本极低,集合新增/删除内容、用户新增/删除集合持有关系时,仅需要写入/删除对应单条条目,不会出现指数级数据膨胀,也不存在一致性问题。
内容的提问来源于stack exchange,提问作者Mert Akozcan
相关产品推荐
相关产品推荐

