基于Python Boto3的DynamoDB时间范围查询问题排查与优化
问题解决与优化方案
1. 错误根源修复
你遇到的'str' object has no attribute 'between'错误,是因为current_time是字符串类型,不能直接调用between方法。DynamoDB的条件表达式需要用boto3.dynamodb.conditions.Attr来构建,而非直接操作字符串。
同时你的scan函数定义了self参数,但它并不是类方法,这个参数需要移除,否则调用时会报错。
2. 正确的Scan实现代码
以下是修正后的Lambda代码,直接使用HH:MM格式的字符串进行时间范围判断(因为HH:MM的字典序和时间顺序完全一致,可直接比较):
import json import boto3 from boto3.dynamodb.conditions import Attr from datetime import datetime def scan(table_name, region, filter_expression, projection_expression): dynamodb_resource = boto3.resource("dynamodb", region_name=region) table = dynamodb_resource.Table(table_name) response = table.scan( FilterExpression=filter_expression, ProjectionExpression=projection_expression ) return response def lambda_handler(event, context): now = datetime.now() current_time = now.strftime("%H:%M") # 构建正确的过滤条件:当前时间 >= fromTime 且 当前时间 <= toTime fe = Attr('fromTime').lte(current_time) & Attr('toTime').gte(current_time) pe = 'user_id' availableUserIDs = scan('availabilities', 'us-east-1', fe, pe)['Items'] return { 'statusCode': 200, 'body': json.dumps(availableUserIDs) }
3. Scan vs Query的选择
DynamoDB的Query只能针对**主键(分区键+排序键)或全局二级索引(GSI)**的键值进行查询,无法直接基于非键字段做范围筛选。你的需求是过滤任意符合时间范围的记录,没有合适的主键/GSI可以利用,因此只能使用Scan。
如果你的表数据量较大(超过10万条),Scan的性能会下降,此时建议优化表结构:
- 新增
fromMinutes和toMinutes字段,存储时间对应的午夜以来分钟数(例如"08:30"转为510,"16:00"转为960) - 为这两个字段创建全局二级索引,后续可以通过
Query或带条件的Scan提升效率
4. 时间转分钟数的实现方案
如果选择用分钟数进行比较,需要在写入数据时预先计算并存储fromMinutes和toMinutes,查询时将当前时间也转为分钟数,再构建过滤条件:
写入数据时的转换逻辑示例
def time_to_minutes(time_str): hours, minutes = map(int, time_str.split(":")) return hours * 60 + minutes # 写入数据时调用 from_min = time_to_minutes("08:30") to_min = time_to_minutes("18:00")
查询时的过滤条件
current_minutes = time_to_minutes(current_time) fe = Attr('fromMinutes').lte(current_minutes) & Attr('toMinutes').gte(current_minutes)
内容的提问来源于stack exchange,提问作者CrimsonDay
相关产品推荐
相关产品推荐

