Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DynamoDB: No way to combine multiple ConditionExpression #4112

Closed
1 of 2 tasks
SamStephens opened this issue May 3, 2024 · 3 comments
Closed
1 of 2 tasks

DynamoDB: No way to combine multiple ConditionExpression #4112

SamStephens opened this issue May 3, 2024 · 3 comments
Labels
feature-request This issue requests a feature. needs-triage This issue or PR still needs to be triaged.

Comments

@SamStephens
Copy link

Describe the feature

According to https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html it's possible to combine multiple conditions using AND and OR. However, from my reading of https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/update_item.html and https://boto3.amazonaws.com/v1/documentation/api/latest/reference/customizations/dynamodb.html#boto3.dynamodb.conditions.Attr, it is only possible to specify a single condition using the update_item operation.

Use Case

I have an attribute I want to update, but not if the update will decrease the attributes value. The attribute is not necessarily present. So I need my conditional expression to be attribute not exists OR attribute value < my value.

It appears the API supports this conditional expression, but not this SDK.

Proposed Solution

  • Add a super class for boto3.dynamodb.conditions.Attr, maybe boto3.dynamodb.conditions.Condition.
  • Make the ConditionExpression parameter a boto3.dynamodb.conditions.Condition.
  • Give boto3.dynamodb.conditions.Condition three methods, And, Or, and Not, that each do the obvious thing.

Under this scheme, my ConditionExpression would be

ConditionExpression = Condition().Or(Attr(attribute_name).not_exists(), Attr(attribute_name).lt(updated_value))

Other Information

The only way I can see to workaround this is two conditional updates - firstly with not_exists, and then if the check fails because the attribute exists, try the update again with lt.

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

SDK version used

1.34.76

Environment details (OS name and version, etc.)

Ubuntu (Windows Subsystem for Linux)

@SamStephens SamStephens added feature-request This issue requests a feature. needs-triage This issue or PR still needs to be triaged. labels May 3, 2024
@crh23
Copy link

crh23 commented May 3, 2024

Do the classes defined as follows fit your use-case?

class ComparisonCondition(ConditionBase):
expression_format = '{0} {operator} {1}'
class Equals(ComparisonCondition):
expression_operator = '='
class NotEquals(ComparisonCondition):
expression_operator = '<>'
class LessThan(ComparisonCondition):
expression_operator = '<'
class LessThanEquals(ComparisonCondition):
expression_operator = '<='
class GreaterThan(ComparisonCondition):
expression_operator = '>'
class GreaterThanEquals(ComparisonCondition):
expression_operator = '>='
class In(ComparisonCondition):
expression_operator = 'IN'
has_grouped_values = True
class Between(ConditionBase):
expression_operator = 'BETWEEN'
expression_format = '{0} {operator} {1} AND {2}'
class BeginsWith(ConditionBase):
expression_operator = 'begins_with'
expression_format = '{operator}({0}, {1})'
class Contains(ConditionBase):
expression_operator = 'contains'
expression_format = '{operator}({0}, {1})'
class Size(ConditionAttributeBase):
expression_operator = 'size'
expression_format = '{operator}({0})'
class AttributeType(ConditionBase):
expression_operator = 'attribute_type'
expression_format = '{operator}({0}, {1})'
class AttributeExists(ConditionBase):
expression_operator = 'attribute_exists'
expression_format = '{operator}({0})'
class AttributeNotExists(ConditionBase):
expression_operator = 'attribute_not_exists'
expression_format = '{operator}({0})'
class And(ConditionBase):
expression_operator = 'AND'
expression_format = '({0} {operator} {1})'
class Or(ConditionBase):
expression_operator = 'OR'
expression_format = '({0} {operator} {1})'
class Not(ConditionBase):
expression_operator = 'NOT'
expression_format = '({operator} {0})'

You can write expressions like
ConditionExpression = Or(Attr(attribute_name).not_exists(), Attr(attribute_name).lt(updated_value))

I'm not sure if they are documented anywhere

@SamStephens
Copy link
Author

@crh23 thanks, this is exactly what I needed.

I've closing this issue as support is present, and replacing it with an issue for the missing documentation.

Copy link

github-actions bot commented May 6, 2024

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request This issue requests a feature. needs-triage This issue or PR still needs to be triaged.
Projects
None yet
Development

No branches or pull requests

2 participants