1

Similar to: I cannot query my dynamodb table from aws lambda due to wrong filterexpression? and DynamoDB update error Invalid UpdateExpression: An expression attribute value used in expression is not defined

I am trying to code a way to query DynamoDB tables using partial matches on Partition Key / Sort Key in Java.

The DynamoDB table I am trying to access has a Partition key of "Type" (A restricted key word in DynamoDB, I know, but not my choice) and a Sort key of "Id". I know the "Type" but not the full Id, so I have researched the Query method using AWS SDK 2.x source code and have implemented as shown below:

DynamoDBClient dynamoDbClient = DynamoDbClient.builder()
  .region(Region.EU_WEST_1)
  .credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
  .build();

String idKey = "wholeIdKey";
String idValue = "partialIdValue";
String typeValue = "typeValue";

Map<String, String> expressionNames = new HashMap<>();
expressionNames.put("#t", "Type");

QueryRequest request = QueryRequest.builder()
  .tableName(tableName)
  .keyConditionExpression("begins_with ( " + idKey + ", :" + idValue + " )
     AND #t = :" + typeValue)
  .expressionAttributeNames(expressionNames)
  .build();

QueryResponse response = dynamoDbClient.query(request);

However, when I run this code, I get the following error message:

Exception in thread "main" software.amazon.awssdk.services.dynamodb.model.DynamoDbException: 
Invalid KeyConditionExpression: An expression attribute value used in expression is not defined; attribute value: :typeValue

It's as if it's not recognizing the fact that I have told the code use the Expression Attribute Names feature to replace the "#t" with "Type" (Which is a reserved keyword in DynamoDB)

Can anyone help?

EDIT: References for code:

https://docs.aws.amazon.com/code-samples/latest/catalog/javav2-dynamodb-src-main-java-com-example-dynamodb-Query.java.html

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html

https://www.javadoc.io/static/software.amazon.awssdk/dynamodb/2.7.14/software/amazon/awssdk/services/dynamodb/model/QueryRequest.html#expressionAttributeNames--

3 Answers 3

2

The name is fine, but you're prefixing both values with ':'. That causes a lookup in ExpressionAttributeValues, which you did not provide.

Never try to write dynamic values directly into the query string.

Sign up to request clarification or add additional context in comments.

3 Comments

Okay, so should I remove the colon if I'm trying to write direct values instead of Expression Attribute Values?
Amazon doesn't document any way to write the values directly in the expression.
Ahh okay. thanks. I provided ExpressionAttributeValues and it's working. Ta.
1

Your expressionAttributeName looks fine, but you forgot to provide a value for :typeValue so dynamoDB cannot know what to look for.

In addition to what you did, you need to add an expressionAttributeValue where you can provide proper values. See documentation here

Comments

0

Fixed Code for whoever wants it in the future (Thanks to @aherve and @MattTimmermans)

DynamoDBClient dynamoDbClient = DynamoDbClient.builder()
  .region(Region.EU_WEST_1)
  .credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
  .build();

String idKey = "wholeIdKey";
String idValue = "partialIdValue";
String typeValue = "typeValue";
String typeKey = "typeKey";

Map<String, String> expressionNames = new HashMap<>();
expressionNames.put("#t", "Type");
expressionNames.put("#i", "Id");

Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":typeName", AttributeValue.builder().s(typeValue).build());
expressionValues.put(":idName", AttributeValue.builder().s(idValue).build());

QueryRequest request = QueryRequest.builder()
  .tableName(tableName)
  .keyConditionExpression("#t = :typeName AND begins_with ( #i, :idName )")
  .expressionAttributeNames(expressionNames)
  .expressionAttributeValues(expressionValues)
  .build();

response = dynamoDbClient.query(request);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.