使用boto3向DynamoDB条件插入数据遇ConditionalCheckFailedException
问题原因及解决方案
问题根源
你写的ConditionExpression逻辑完全不符合需求:
- 当前条件
attribute_exists(#equipment_id) AND attribute_exists(#edt_id) AND attribute_exists(#location_id)检查的是与要插入条目主键相同的现有条目是否包含这三个属性。 - 如果你要插入的是新条目(表中无相同主键的记录),这个条件会直接判定失败——因为不存在对应主键的条目,自然没有这些属性,所以触发
ConditionalCheckFailedException。 - 你的实际需求是检查表中是否存在任意包含这三个属性的条目,而不是针对同主键的条目。
正确实现方式
DynamoDB的PutItem接口无法直接跨条目做条件检查,必须先查询表中是否存在符合要求的条目,再决定是否插入:
dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('my_table_dev') # 先查询是否存在包含指定三个属性的条目 scan_response = table.scan( FilterExpression='attribute_exists(#equipment_id) AND attribute_exists(#edt_id) AND attribute_exists(#location_id)', ExpressionAttributeNames={"#equipment_id": "equipment_id", "#edt_id": "edt_id", "#location_id": "location_id"}, Limit=1 # 只需找到一个匹配条目即可,无需全表扫描 ) if scan_response['Count'] > 0: # 存在符合条件的条目,执行插入 table.put_item( Item={ 'event_id': 1, 'timestamp': 1538586609, 'bit_value': 6, 'category': 'alarm', 'edt_id': 3684824, 'equipment_id': 3440153, 'event_date': '2018-10-03T17:10:09', 'event_type_id': 35, 'event_type_name': 'Others', 'event_val': 1, 'location_id': 3405207 } ) else: print("表中无包含equipment_id、edt_id、location_id属性的条目,跳过插入")
优化建议
如果这个检查操作频繁执行,全表Scan的效率会很低,建议:
- 创建全局二级索引(GSI),将
equipment_id设为分区键,edt_id和location_id设为排序键(或组合成一个属性作为排序键)。 - 之后用
Query替代Scan,大幅提升查询效率。
内容的提问来源于stack exchange,提问作者Stéphane GRILLON
相关产品推荐
相关产品推荐

