Dynamodb scan()使用FilterExpression

时间:2017-06-22 16:04:56

标签: python python-2.7 amazon-dynamodb

首先发布在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个字段。

  1. ID
  2. 日期
  3. 安全
  4. DynamoDB Pic

    现在针对这个问题,在运行时我得到两个表条目,当我应该只获得第一个条目时...根据我的扫描标准“没有安全问题”。

    ---这是我的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。我试图保持帖子简单易懂(不包括我的所有程序代码)但是,如果需要其他信息,我可以提供!

4 个答案:

答案 0 :(得分:3)

这是因为您在表达式中使用了Python的and关键字,而不是&运算符。

如果ab都被视为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)

根据the documentation

  

您还可以使用逻辑链将条件链接在一起   运营商:& (和),| (或),和〜(不)。

答案 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]