Reputation: 371
I'm having trouble running a query against a secondary index, getting an exception:
Ex getting dynamodb scan: java.lang.IllegalArgumentException: Attempt to execute an operation that requires a secondary index without defining the index attributes in the table metadata. Index name: category-timestamp-index
Can someone guide me on how I'm doing this wrong?
My table is idIT_RSS_Sources and I've created an index category-timestamp-index.
[]]1
My code is:
DynamoDbEnhancedClient enhancedClient = getEnhancedDBClient(region);
// Create a DynamoDbTable object
logger.debug("getting RSS Source category-timestamp-index");
//this throws the exception
DynamoDbIndex<RSS_Source> catIndex =
enhancedClient.table("idIT_RSS_Sources",
TableSchema.fromBean(RSS_Source.class))
.index("category-timestamp-index");
logger.debug("building query attributes");
AttributeValue att = AttributeValue.builder()
.s(theCategory)
.build();
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":value", att);
Expression expression = Expression.builder()
.expression("category = :value")
.expressionValues(expressionValues)
.build();
// Create a QueryConditional object that's used in the query operation
QueryConditional queryConditional = QueryConditional
.keyEqualTo(Key.builder().partitionValue(theCategory)
.build());
logger.debug("calling catIndex.query in getRSS...ForCategory");
Iterator<Page<RSS_Source>> dbFeedResults = (Iterator<Page<RSS_Source>>) catIndex.query(
QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.build());
Upvotes: 10
Views: 20372
Reputation: 46
Make sure your DynamoDbBean has correct getters and setters for the GSIPK and GSISK.
Confirm your index is correctly defined by debugging the result of TableSchema.fromBean(YourBean.class)
and inspecting inside the delegates -> tableMetadata -> indexByNameMap should have your index name.
Upvotes: 1
Reputation: 10734
Assume you have a model named Issues.
package com.example.dynamodb;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
@DynamoDbBean
public class Issues {
private String issueId;
private String title;
private String createDate;
private String description;
private String dueDate;
private String status;
private String priority;
private String lastUpdateDate;
@DynamoDbPartitionKey
public String getId() {
return this.issueId;
}
public void setId(String id) {
this.issueId = id;
}
@DynamoDbSortKey
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public void setLastUpdateDate(String lastUpdateDate) {
this.lastUpdateDate = lastUpdateDate;
}
public String getLastUpdateDate() {
return this.lastUpdateDate;
}
public void setPriority(String priority) {
this.priority = priority;
}
public String getPriority() {
return this.priority;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return this.status;
}
public void setDueDate(String dueDate) {
this.dueDate = dueDate;
}
@DynamoDbSecondaryPartitionKey(indexNames = { "dueDateIndex" })
public String getDueDate() {
return this.dueDate;
}
public String getDate() {
return this.createDate;
}
public void setDate(String date) {
this.createDate = date;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
Notice the annotation on getDueDate
.
@DynamoDbSecondaryPartitionKey(indexNames = { "dueDateIndex" })
public String getDueDate() {
return this.dueDate;
}
This is because the Issues table has a secondary index named dueDateIndex
.
To query on this secondary index, you can use this code that uses the Amazon DynamoDB Java API V2:
public static void queryIndex(DynamoDbClient ddb, String tableName, String indexName) {
try {
// Create a DynamoDbEnhancedClient and use the DynamoDbClient object
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
//Create a DynamoDbTable object based on Issues
DynamoDbTable<Issues> table = enhancedClient.table("Issues", TableSchema.fromBean(Issues.class));
String dateVal = "2013-11-19";
DynamoDbIndex<Issues> secIndex =
enhancedClient.table("Issues",
TableSchema.fromBean(Issues.class))
.index("dueDateIndex");
AttributeValue attVal = AttributeValue.builder()
.s(dateVal)
.build();
// Create a QueryConditional object that's used in the query operation
QueryConditional queryConditional = QueryConditional
.keyEqualTo(Key.builder().partitionValue(attVal)
.build());
// Get items in the Issues table
SdkIterable<Page<Issues>> results = secIndex.query(
QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.build());
AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.set(0);
results.forEach(page -> {
Issues issue = (Issues) page.items().get(atomicInteger.get());
System.out.println("The issue title is "+issue.getTitle());
atomicInteger.incrementAndGet();
});
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
Upvotes: 11
Reputation: 764
For what it's worth, if your Global Secondary Index has a sort key, you must annotate that field in the DynamoDB bean with:
@DynamoDbSecondarySortKey(indexNames = { "<indexName>" })
public String getFieldName() {
return fieldName;
}
Upvotes: 5
Reputation: 371
solved, I was not using the proper annotation in my model class:
@DynamoDbSecondaryPartitionKey(indexNames = { "category-index" })
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
Upvotes: 17
Reputation: 8359
My working code is as below: sortKey-index = GSI in dynamo db
List<Flow> flows = new ArrayList<>();
DynamoDbIndex<Flow> flowBySortKey = table().index("sortKey-index");
// Create a QueryConditional object that's used in the query operation
QueryConditional queryConditional = QueryConditional
.keyEqualTo(Key.builder()
.partitionValue(sortKey)
.build());
SdkIterable<Page<Flow>> dbFeedResults = flowBySortKey.query(
QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.build());
dbFeedResults.forEach(flowPage -> {
flows.addAll(flowPage.items());
});
Upvotes: 0