Home > front end >  Why am I getting "The provided key element does not match the schema" error with Java Dyna
Why am I getting "The provided key element does not match the schema" error with Java Dyna

Time:12-27

I'm trying to implement with DynamoDB a way to allow items to be only inserted and NOT updated/replaced (to achieve some level of transaction control). Therefore, I have the following DB Schema configured in AWS DynamoDB:

PartitionKey="driveUniqueId (String)"
SortKey="createTime (String)"

Now, if I run the following snippet of code, the operation works and the record is created.

String currentTime = LocalTime.now().toString();
dynamoDbClient.transactWriteItems(TransactWriteItemsRequest.builder()
  .transactItems(
    TransactWriteItem.builder().put(
      Put.builder()
        .tableName(tableName)
        .item(Map.of(
          "driveUniqueId", AttributeValue.builder().s("789").build(),
          "createTime", AttributeValue.builder().s(currentTime).build()))
      .build())
    .build())
  .build());

However, If I run the following snippet of code adding the conditionCheck to prevent replaces, then I get the following error:

dynamoDbClient.transactWriteItems(TransactWriteItemsRequest.builder()
  .transactItems(
    TransactWriteItem.builder().put(
      Put.builder()
        .tableName(tableName)
        .item(Map.of(
          "driveUniqueId", AttributeValue.builder().s("123").build(),
          "createTime", AttributeValue.builder().s(currentTime).build()))
      .build())
    .build(),
    TransactWriteItem.builder().conditionCheck(
      ConditionCheck.builder()
        .tableName(tableName)
        .key(Map.of(
          "driveUniqueId", AttributeValue.builder().s("123").build()))                                    
        .conditionExpression("attribute_not_exists(driveUniqueId)")
      .build())
    .build())
  .build());
/*
Error: 
CancellationReason(Code=None)
CancellationReason(Code=ValidationError, Message=The provided key element does not match the schema)
*/

I don't understand why the condition specified can't understand the "driveUniqueId" as part of the schema in the second write operation. I'm running this code using Quarkus, Java 17, and AWS SDK 2.17.291. Any ideas why my conditionCheck is wrong?

CodePudding user response:

Your condition check is causing a validation error because you did not include the items sork key createTime.

As with any write to DynamoDB you must include the full primary key, partition and sort key.

Furthermore, you possibly do not need to use transactions, single item operations are ACID compliant, so you could simply use a PutItem with a condition check.

CodePudding user response:

This is my final solution based on @Lee Hanningan response.

/**
 * This method guarantees that a Item with a {@param uniqueId} will be processed only once
 * by the POD who grabbed its lock (a.k.a. being the first to insert the Item into DynamoDB table).
 * If another POD tries to re-process the same Item in parallel or in the future it'll fail.
 *
 * This property guarantees that Item will contribute to the process only once, in case of a POD 
 * network partition not acknowledging to SQS that a Item was processed successfully.
 *
 * @param uniqueId
 * @return isItemLocked.
 */
public boolean insertAndLockProcessingToItem(final String uniqueId) {
    boolean itemLockedToBeProcessed;
    try {
        String currentTime = LocalDateTime.now().toString();
        dynamoDbClient.putItem(PutItemRequest.builder()
            .tableName(TABLE_NAME)
            .item(Map.of(
                "uniqueId", AttributeValue.builder().s(uniqueId).build(),
                "createTime", AttributeValue.builder().s(currentTime).build()))
            .conditionExpression("attribute_not_exists(uniqueId)")
        .build());
        itemLockedToBeProcessed = true;
    } catch (final ConditionalCheckFailedException ccfe) {
        itemLockedToBeProcessed = false;
    } catch (final Exception ex) {
        throw new RuntimeException(ex);
    }
    return itemLockedToBeProcessed;
}
  • Related