[英]FilterExpression Syntax error using boto3 dynamodb client
[英]Dynamodb scan() using FilterExpression
第一次在 Stack 上发帖,对使用 Python 和使用 DynamoDB 编程还很陌生,但我只是尝试在我的表上运行扫描,返回基于两个预定义属性的结果。
---这是我的 Python 代码片段---
shift = "3rd"
date = "2017-06-21"
if shift != "":
response = table.scan(
FilterExpression=Attr("Date").eq(date) and Attr("Shift").eq(shift)
)
我的 DynamoDB 有 4 个字段。
现在对于这个问题,在运行时,当我应该只获取第一个条目时,我返回了两个表条目......根据我的扫描标准,“没有安全问题”。
---这是我的 DynamoDB 返回结果---
[
{
"Shift": "3rd",
"Safety": "No safety issues",
"Date": "2017-06-21",
"ID": "2"
},
{
"Shift": "3rd",
"Safety": "Cut Finger",
"Date": "2017-06-22",
"ID": "4"
}
]
退回的物品:2
我相信通过应用带有逻辑“and”的 FilterExpression 指定扫描操作正在寻找满足两个条件的条目,因为我使用了“and”。
这可能是因为在两个条目中都找到了 'shift' 属性“3rd”? 我如何确保它返回基于满足 BOTH 标准的条目,而不仅仅是给我来自一种属性类型的结果?
我觉得这很简单,但我查看了以下可用文档: http : //boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.Table.scan并且仍然遇到问题. 任何帮助将不胜感激!
PS 我尽量让帖子简单易懂(不包括我所有的程序代码)但是,如果需要其他信息,我可以提供!
这是因为您在表达式中使用了 Python 的and
关键字,而不是&
运算符。
如果a
和b
都被认为是True
, a and b
返回后者, b
:
>>> 2 and 3
3
如果它们中的任何一个是False
,或者如果它们两个都是,则返回第一个False
对象:
>>> 0 and 3
0
>>> 0 and ''
0
>>>
一般规则是, and
返回第一个允许它决定整个表达式的真实性的对象。
Python 对象在布尔上下文中始终被视为True
。 所以,你的表达:
Attr("Date").eq(date) and Attr("Shift").eq(shift)
将评估为最后一个True
对象,即:
Attr("Shift").eq(shift)
这解释了为什么您只对班次进行过滤。
您需要使用&
运算符。 它通常表示 Python 中整数之间的“按位和”,它被重新定义为 Attr 对象以表示您想要的内容:“两个条件”。
所以你必须使用“按位与”:
FilterExpression=Attr("Date").eq(date) & Attr("Shift").eq(shift)
根据文档,
您还可以使用逻辑运算符将条件链接在一起:&(和)、| (或)和~(不是)。
Dynamodb scan() 使用 FilterExpression
对于多个过滤器,您可以使用这种方法:
import boto3
from boto3.dynamodb.conditions import Key, And
filters = dict()
filters['Date'] = "2017-06-21"
filters['Shift'] = "3rd"
response = table.scan(FilterExpression=And(*[(Key(key).eq(value)) for key, value in filters.items()]))
使用上述每个答案中的部分,这是我能够使其工作的紧凑方式:
from functools import reduce
from boto3.dynamodb.conditions import Key, And
response = table.scan(FilterExpression=reduce(And, ([Key(k).eq(v) for k, v in filters.items()])))
允许根据filters
中的多个条件作为dict
进行filters
。 例如:
{
'Status': 'Approved',
'SubmittedBy': 'JackCasey'
}
扩展 Maxime Paille 的回答,这涵盖了只有一个过滤器而不是多个过滤器的情况。
from boto3.dynamodb.conditions import And, Attr
from functools import reduce
from operator import and_
filters = dict()
filters['Date'] = "2017-06-21"
filters['Shift'] = "3rd"
table.scan("my-table", **build_query_params(filters))
def build_query_params(filters):
query_params = {}
if len(filters) > 0:
query_params["FilterExpression"] = add_expressions(filters)
return query_params
def add_expressions(self, filters: dict):
if filters:
conditions = []
for key, value in filters.items():
if isinstance(value, str):
conditions.append(Attr(key).eq(value))
if isinstance(value, list):
conditions.append(Attr(key).is_in([v for v in value]))
return reduce(and_, conditions)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.