python dynamodb构造动态查询结合布尔运算

时间:2018-02-09 00:34:54

标签: python amazon-web-services amazon-dynamodb boto3

boto3&rsod; dynamodb的AWS示例过于简单化。我想抛出一个Web表单,允许用户选择表中的任何元素,或者为任何单个字段和AND所有字段过滤器提供多个选项。

要做到这一点,我需要构建一系列OR条件,然后和所有结果或组合,如: 和([或([c1,c2,...]),或([e1,e ...]),或([a1,a ...])])

我不知道每个Or的术语数量,或者直到运行时的最终和,所以我需要能够在运行时聚合过滤器术语。

对于下面的所有问题,这里是我的FilterExpressions集:

c1 = Attr('class').eq(2)
c2 = Attr('class').eq(3)
c = Or([c1, c2])

e1 = Attr('exclusion').eq(0)

a1 = Attr('action').eq(2)

我能够进行简单的和/或查询:

结合2和条件:

all = [a1, e1]
request = {'ConsistentRead': False, 'FilterExpression': And(*all)}
print ('dynamo scan params: {}'.format(request))
response = table.scan(**request)
print response['Count'], response['ScannedCount']
dynamo scan params: {'FilterExpression': <boto3.dynamodb.conditions.And object at 0x115d7d410>, 'ConsistentRead': False}
34 1166

结合2或条件:

all = [c1,c2]
request = {'ConsistentRead': False, 'FilterExpression': Or(*all)}
print ('dynamo scan params: {}'.format(request))
response = table.scan(**request)
print response['Count'], response['ScannedCount']
dynamo scan params: {'FilterExpression': <boto3.dynamodb.conditions.Or object at 0x115d7dc90>, 'ConsistentRead': False}
51 1166

结合多个And和Or条件:

我希望此处的语法不正确,但我无法在AWS或boto文档中找到任何此类示例。

all = [And([a1,e1]), Or([c1,c2])]

那就是我被困的地方。

1 个答案:

答案 0 :(得分:0)

这有效,但感觉不是很理想:

            # 2 params are clazz and exclusion which are lists of matches
            # to be OR's together individually and ANDed at the end.
            # these map to the dynamo fields 'class' and 'exclusion'

            # Start with an empty aggregator filter:
            fe = None

            # I'm iterating over each "OR" item:
            # class is a list of enum values that should match in an OR condition
            if clazz:
                fe_class = None
                for x in clazz:
                    fe_x = Attr('class').eq(ArticleClass[x].value)
                    if not fe_class:
                        fe_class = fe_x
                    else:
                        fe_class = (fe_class | fe_x)

                # Then appending it as an "AND" item to a running total:

                if fe:
                    # If there's an existing fe, append this
                    fe = (fe & fe_class)
                else:
                    # otherwise this is the starting point
                    fe = fe_class

            # Next "OR" term
            # exclusion is also a list of enum values that should match in an OR condition
            if exclusion:
                fe_exclusion = None
                for x in exclusion:
                    fe_x = Attr('exclusion').eq(ArticleExclusion[x].value)
                    if not fe_exclusion:
                        fe_exclusion = fe_x
                    else:
                        fe_exclusion = (fe_exclusion | fe_x)

                # "AND"ed together again:
                if fe:
                    # If there's an existing fe, append this
                    fe = (fe & fe_exclusion)
                else:
                    # otherwise this is the starting point
                    fe = fe_exclusion

            # If the aggregated filter has any Attr's in it, add to request
            if fe:
                request['FilterExpression'] = fe

            response = table.scan(**request)

喜欢知道是否有更好的方式。