0

I have a DynamoDB table which has 3 attributes(partition key - id, sortkey - orderId, info). I am trying to write into DynamoDB if the record does not exist(either the partition key or the sort key) already. My code snippet as below

public void saveRecord(@NonNull Payload payload) {

        final String id = payload.getId();
        final String orderId = payload.getOrderId();

            Map<String, ExpectedAttributeValue> expectedAttributes =
                    ImmutableMap.<String, ExpectedAttributeValue>builder()
                            .put(id, new ExpectedAttributeValue().withExists(false))
                            .put(orderId, new ExpectedAttributeValue().withExists(false))
                            .build();

            DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression()
                    .withExpected(expectedAttributes)
                    .withConditionalOperator(ConditionalOperator.OR);

            ObjectToSave objectToSave = ObjectToSave.builder()
                    .id(id)
                    .sortKey(orderId)
                    .info(payload.getInfo())
                    .build();

            try {
            dynamoDBMapper.save(objectToSave, saveExpression);
            log.info("write successful");
        } catch (ConditionalCheckFailedException e) {
            log.error("Record already exists id:{}, sortKey: {}", id, orderId);
        }
    }

My understanding is whenever I receive a record that already exists in the table, the above code should log the error statement. But It's not happening like that. What am I missing here or doing wrong?

1 Answers1

1

This is because you pass in the AttributeValue of the partition and sort key, rather than the AttributeNames:

public void saveRecord(@NonNull Payload payload) {

        final String id = payload.getId();
        final String orderId = payload.getOrderId();

            Map<String, ExpectedAttributeValue> expectedAttributes =
                    ImmutableMap.<String, ExpectedAttributeValue>builder()
                            .put("id", new ExpectedAttributeValue().withExists(false))
                            .put("orderId", new ExpectedAttributeValue().withExists(false))
                            .build();

            DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression()
                    .withExpected(expectedAttributes)
                    .withConditionalOperator(ConditionalOperator.OR);

            ObjectToSave objectToSave = ObjectToSave.builder()
                    .id(id)
                    .sortKey(orderId)
                    .info(payload.getInfo())
                    .build();

            try {
            dynamoDBMapper.save(objectToSave, saveExpression);
            log.info("write successful");
        } catch (ConditionalCheckFailedException e) {
            log.error("Record already exists id:{}, sortKey: {}", id, orderId);
        }
    }
Leeroy Hannigan
  • 11,409
  • 3
  • 14
  • 31
  • ahh, yes!! that worked. but I am curious how does this work? My understanding is I should provide the id and OrderId to check if those exact id and Order Id is present. If I just provide the partitionkey and sortkey attribute name, how does it check against the value? – Conquistador Feb 20 '23 at 19:46
  • Because you must also pass the Partition and Sort key values as part of the request which indicates the item. Conditions are only evaluated for a single item. – Leeroy Hannigan Feb 20 '23 at 20:09
  • If I understand it right, from the AWSDoc(https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/model/ExpectedAttributeValue.html#withExists-java.lang.Boolean-), it says ```DynamoDB returns a ValidationException if: Exists is false but you also provide a Value.```. So I assume, we can not provide an attribute value while saying it does not exist. correct me if I am wrong. – Conquistador Feb 20 '23 at 21:08
  • I'm not sure I get your question? Your goal is to write if an item does not exist. You can achieve that with the condition I shared, as it evaluates if a value exists for the given PK/SK combo for that item. – Leeroy Hannigan Feb 20 '23 at 23:19