如何在DynamoDB中基于排序键而非分区键查询数据?
解决DynamoDB仅用排序键查询的报错问题
嘿,这个报错我太熟悉了——这是DynamoDB的核心规则在起作用:Query操作必须指定分区键(也就是你的表中的ID)。因为Query是基于主键(分区键+排序键)的定向查询,排序键只能作为分区键的补充来做范围过滤,单独拿排序键当查询条件是不被允许的,这就是你看到Query condition missed key schema element: ID的根本原因。
针对你要检索所有Updated大于"2018-02-01"记录的需求,我给你两种靠谱的解决方案,拆解得明明白白:
方案一:创建全局二级索引(GSI)【推荐生产环境使用】
这是最贴合DynamoDB设计理念的做法。你可以给表创建一个以Updated为分区键的全局二级索引,这样就能通过Query这个索引直接筛选时间范围的记录了。
操作步骤&示例代码(以boto3为例)
- 给表添加GSI:
import boto3 from boto3.dynamodb.conditions import Key dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('你的表名') # 更新表结构,添加以Updated为分区键的GSI table.update( AttributeDefinitions=[ { 'AttributeName': 'Updated', 'AttributeType': 'S' # 匹配你表中Updated的字符串类型日期 } ], GlobalSecondaryIndexUpdates=[ { 'Create': { 'IndexName': 'Updated-index', 'KeySchema': [ { 'AttributeName': 'Updated', 'KeyType': 'HASH' } ], 'Projection': { 'ProjectionType': 'ALL' # 可按需选择只投影需要的字段,降低存储成本 }, 'ProvisionedThroughput': { 'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5 } } } ] )
- 通过GSI执行Query查询:
response = table.query( IndexName='Updated-index', KeyConditionExpression=Key('Updated').gt('2018-02-01') ) items = response['Items'] # 按需处理查询结果
方案二:使用Scan操作【仅临时/小数据量场景使用】
如果只是临时查询或者表的数据量极小,可以用Scan来全表过滤,但必须提醒你:Scan会遍历表中所有数据,数据量大时不仅速度慢,还会消耗更多读写容量,成本很高,绝对不推荐在生产环境的大数据量表上使用。
示例代码
from boto3.dynamodb.conditions import Attr response = table.scan( FilterExpression=Attr('Updated').gt('2018-02-01') ) items = response['Items'] # 数据量大时需处理分页 while 'LastEvaluatedKey' in response: response = table.scan( FilterExpression=Attr('Updated').gt('2018-02-01'), ExclusiveStartKey=response['LastEvaluatedKey'] ) items.extend(response['Items'])
额外小提示
如果你的需求是针对某个特定ID,查询它的Updated大于某个值,那直接用原始表的Query就行,比如:
response = table.query( KeyConditionExpression=Key('ID').eq('1201') & Key('Updated').gt('2018-02-01') )
内容的提问来源于stack exchange,提问作者Octopus




