使用FilterExpression的Dynamodb scan()

Tor*_*byn 7 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)
    )
Run Code Online (Sandbox Code Playgroud)

我的DynamoDB有4个字段。

  1. ID
  2. 日期
  3. 转移
  4. 安全

DynamoDB图片

现在,针对该问题,在运行时,我将获得两个表条目,而我仅应获得第一个条目...根据我的扫描标准,该条目具有“无安全问题”。

---这是我的DynamoDB返回结果---

[
  {
    "Shift": "3rd",  
    "Safety": "No safety issues",  
    "Date": "2017-06-21",
    "ID": "2"
  }, 
  {
    "Shift": "3rd", 
    "Safety": "Cut Finger", 
    "Date": "2017-06-22", 
    "ID": "4"
  }
]
Run Code Online (Sandbox Code Playgroud)

返回的项目:2

我相信,通过将FilterExpression与逻辑“和”一起应用,可以指定扫描操作正在查找满足两个条件的条目,因为我使用了“和”。

可能是因为在两个条目中都找到了“ shift”属性“ 3rd”吗?如何确保它根据两个条件都满足而返回条目,而不仅仅是给出一种属性类型的结果?

我觉得这很简单,但是我在以下位置查看了可用的文档:http : //boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.Table.scan,仍然遇到问题。任何帮助将不胜感激!

PS我试图使文章简单易懂(不包括我的所有程序代码),但是,如果需要其他信息,我可以提供!

Thi*_*lle 7

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

如果ab都认为Truea and b返回后,b

>>> 2 and 3
3
Run Code Online (Sandbox Code Playgroud)

如果它们中的任何一个是False,或者如果它们两个都是,False则返回第一个对象:

>>> 0 and 3
0
>>> 0 and ''
0
>>> 
Run Code Online (Sandbox Code Playgroud)

一般规则是,and返回允许其确定整个表达式的真实性的第一个对象。

始终True在布尔上下文中考虑Python对象。所以,你的表情:

Attr("Date").eq(date) and Attr("Shift").eq(shift)
Run Code Online (Sandbox Code Playgroud)

将评估为最后一个True对象,即:

Attr("Shift").eq(shift)
Run Code Online (Sandbox Code Playgroud)

这就解释了为什么您只对班次进行过滤。

您需要使用&运算符。它通常在Python中的整数之间表示“按位与”,为Attr对象重新定义它以表示您想要的内容:“两个条件”。

因此,您必须使用“按位与”:

FilterExpression=Attr("Date").eq(date) & Attr("Shift").eq(shift)
Run Code Online (Sandbox Code Playgroud)

根据文档

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


Max*_*llé 6

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()]))
Run Code Online (Sandbox Code Playgroud)


bru*_*ski 5

扩展 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)
Run Code Online (Sandbox Code Playgroud)


Jac*_*sey 5

使用上述每个答案中的部分,这是我能够使其工作的紧凑方式:

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()])))

Run Code Online (Sandbox Code Playgroud)

允许过滤多个条件filters作为dict. 例如:

{
    'Status': 'Approved', 
    'SubmittedBy': 'JackCasey'
}
Run Code Online (Sandbox Code Playgroud)