简体   繁体   English

DynamoDB Query FilterExpression 多条件链接 Python

[英]DynamoDB Query FilterExpression Multiple Condition Chaining Python

I am trying to programmatically create a FilterExpression in Python for a DynamoDB query based on user provided parameter(s) for a specific Attribute (let's call it ' ATTRIBUTE1 ').我正在尝试根据用户提供的特定属性的参数(我们称之为“ ATTRIBUTE1 ”)以编程方式在 Python 中为 DynamoDB 查询创建 FilterExpression。

All user provided parameters which I need to filter for are in a list.我需要过滤的所有用户提供的参数都在列表中。 For example: ['Parameter1', 'Parameter2']例如: ['Parameter1', 'Parameter2']

Which would then take the form Attr('ATTRIBUTE1').eq(PARAMETER1)&Attr.('ATTRIBUTE1').eq(PARAMETER2)然后将采用Attr('ATTRIBUTE1').eq(PARAMETER1)&Attr.('ATTRIBUTE1').eq(PARAMETER2)

How can I programmatically create an Attr for my FilterExpression like the above which is based on a changing number of user provided parameter(s)?如何以编程方式为我的 FilterExpression 创建一个 Attr 像上面那样基于用户提供的参数数量的变化?

Sometimes I might have ['Parameter1'] and another time I might have ['Parameter1', 'Parameter2', 'Parameter3'] which need to turn into Attr('ATTRIBUTE1').eq('Parameter1') and Attr('ATTRIBUTE1').eq('Parameter1')&Attr('ATTRIBUTE1').eq('Parameter2')&Attr('ATTRIBUTE1').eq('Parameter3') , respectively.有时我可能有['Parameter1']和另一个时间我可能有['Parameter1', 'Parameter2', 'Parameter3']需要变成Attr('ATTRIBUTE1').eq('Parameter1')Attr('ATTRIBUTE1').eq('Parameter1')&Attr('ATTRIBUTE1').eq('Parameter2')&Attr('ATTRIBUTE1').eq('Parameter3')分别。

I haven't been able to find a solution for this yet and would appreciate any guidance.我还没有找到解决方案,希望得到任何指导。 Thanks in advance.提前致谢。

You can try the following.您可以尝试以下操作。 I run through the loop of query params to build the dynamodb conditions.我通过查询参数循环来构建 dynamodb 条件。

    if event.get('queryStringParameters'):
        query_params = event.get('queryStringParameters')
        for query_param, value in query_params.items():
            if query_param == 'attribute1':
                filter_expression_list.append(Attr('attribute1').gte(value))
            if query_param == 'attribute2':
                filter_expression_list.append(Attr('attribute2').eq(value))
            if query_param == 'attribute3':
                filter_expression_list.append(Attr('attribute3').eq(value))
    FilterExpression = get_filter_expression(filter_expression_list)

Update:更新:

Can use the following code to get the filter expression.可以使用以下代码获取过滤器表达式。 This will handle the case when there are 2 or more than 2 expressions这将处理有 2 个或 2 个以上表达式的情况

def get_filter_expression(filter_expression_list):
    filter_expression = None
    first = True
    for filter in filter_expression_list:
        if first:
            filter_expression = filter
            first = False
        else:
            filter_expression = filter_expression & filter
    return filter_expression

Here's a compact way I was able to get this working:这是我能够使其工作的紧凑方式:

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

For example, filters would be a dict like:例如, filters将是一个像这样的dict

{
    'Status': 'Approved', 
    'SubmittedBy': 'JackCasey'
}

Combination of FilterExpression in a string form and ExpressionAttributeValues can work, consider following example:字符串形式的 FilterExpression 和 ExpressionAttributeValues 的组合可以工作,请考虑以下示例:

attrs = ["attribute1", "attribute2", "attribute3"]
user_input = ["parameter1", "paramater2", "parameter3"]
ExpressionAttributeValues = {}
FilterExpression = "";
for index, input in enumerate(attrs):
    if(len(attrs)-1 == index): FilterExpression += input+"=:"+input
    else: FilterExpression += input+" = :"+input + " AND ";

for index, input in enumerate(user_input):
    AttrName = ":" + attrs[index]
    ExpressionAttributeValues[AttrName] = {
        "S" : input
    }

print(ExpressionAttributeValues) 
print(FilterExpression)

then you can use these two in your query, more on here http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#client然后你可以在你的查询中使用这两个,更多在这里http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#client

A compact, Pythonic approach might be to manage the criteria in a dictionary, avoid the looping in favor of comprehensions, and use the string format method:一种紧凑的 Pythonic 方法可能是管理字典中的标准,避免循环以支持理解,并使用字符串格式方法:

criteria = {'my_key1': 'my_value1', 'my_key2': 'my_value2'}
FilterExpression = ' AND '.join(['{0}=:{0}'.format(k) for k, v in criteria.items()])
ExpressionAttributeValues = {':{}'.format(k): {'S': v} for k, v in criteria.items()}
i = 0
for key, val in attr_value_dic.items():
    if i == 0:
        filterCondition = Attr(key).eq(val)
    filterConidtion = filterCondition & Attr(key).eq(val) 
    i = i + 1

response = table.query(
    KeyConditionExpression=Key(partition_key).eq(search_value)
    ,FilterExpression=filterCondition

    )  

My solution for chaining multiple filter expression in python.我在python中链接多个过滤器表达式的解决方案。

from boto3.dynamodb.conditions import Key, Attr  
 ...
 users_table_dynamo.query(
    KeyConditionExpression=Key('pk').eq('SC#' + sc_id) & Key('sk').begins_with("GA#"),
    FilterExpression=eval("Attr('attribute1').eq('value1') & Attr('attribute2').eq('value2') & Attr('attribute3').eq('value3')"))

Also i can write something like this, for dynamic expression creation:我也可以写这样的东西,用于动态表达式创建:

def constructFilterExpression(tag_ids):
expression = ""
for idx, item in enumerate(tag_ids):
    if idx == 0:
        expression += f"Attr('user_tag_id').eq('{str(item)}')"
    else:
        expression += f" & Attr('user_tag_id').eq('{str(item)}')"

return expression

so finally my query is:所以最后我的查询是:

filterExpression = constructFilterExpression(tag_ids)
item = users_table_dynamo.query(
    KeyConditionExpression=Key('pk').eq('SC#' + scenario_id) & Key('sk').begins_with("AT#"),
    FilterExpression=eval(filterExpression),
    ProjectionExpression="article_id")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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