首先发布在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
我相信通过应用带有逻辑'和'的FilterExpression指定扫描操作正在寻找符合BOTH标准的条目,因为我使用了'和'。
这可能是因为在两个条目中都找到了'shift'属性“3rd”吗?我如何确保它根据满足的两个条件返回条目,而不仅仅是从一个属性类型给我结果?
我觉得这很简单,但我查看了http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.Table.scan的可用文档,但仍然遇到问题。任何帮助将不胜感激!
P.S。我试图保持帖子简单易懂(不包括我的所有程序代码)但是,如果需要其他信息,我可以提供!
答案 0 :(得分:3)
这是因为您在表达式中使用了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)
您还可以使用逻辑链将条件链接在一起 运营商:& (和),| (或),和〜(不)。
答案 1 :(得分:3)
使用上述每个答案中的部分,这是使我能够正常工作的一种紧凑方式:
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
进行过滤。例如:
{
'Status': 'Approved',
'SubmittedBy': 'JackCasey'
}
答案 2 :(得分:1)
使用FilterExpression的Dynamodb scan()
对于多个过滤器,您可以使用以下方法:
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()]))
答案 3 :(得分:0)
扩展Maxime Paille的答案,它涵盖了仅存在一个过滤器或存在多个过滤器的情况。
from boto3.dynamodb.conditions import And, Attr
filters = dict()
filters['Date'] = "2017-06-21"
filters['Shift'] = "3rd"
table.scan("my-table", **build_query_params(filters))
def build_query_params(filter_expressions):
query_params = {}
if len(filter_expressions) > 0:
query_params["FilterExpression"] = add_expressions(filter_expressions)
return query_params
def add_expressions(expressions: dict):
if len(expressions) > 1:
return And(*[(Attr(key).eq(value)) for key, value in expressions.items()])
elif len(expressions) == 1:
return [(Attr(key).eq(value)) for key, value in expressions.items()][0]