繁体   English   中英

Dynamodb scan() 使用 FilterExpression

[英]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 个字段。

  1. 身份证
  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"
  }
]

退回的物品:2

我相信通过应用带有逻辑“and”的 FilterExpression 指定扫描操作正在寻找满足两个条件的条目,因为我使用了“and”。

这可能是因为在两个条目中都找到了 'shift' 属性“3rd”? 我如何确保它返回基于满足 BOTH 标准的条目,而不仅仅是给我来自一种属性类型的结果?

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

PS 我尽量让帖子简单易懂(不包括我所有的程序代码)但是,如果需要其他信息,我可以提供!

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

如果ab都被认为是Truea 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM