Reputation: 811
I have 500 items to be retrieved using 500 primary key attribute and I want to retrieve 4 attributes of each item instead of all the attributes. I am using DynamoDBMapper in Java, but I am unable to find a way to project them to a specific number of attributes. Retrieving all the attributes might be very costly since one of attributes can be very big. Is there a way to get 4 attributes of all those 500 items using DynamoDBMapper?
Upvotes: 5
Views: 10418
Reputation: 1138
You can use the overloaded scan
Operation of the DynamoDB Table instance and just leave the filter expression empty.
The following Example retrieves only the attributes id
and country
for each table item, even though each record has many more attributes. It's Kotlin, but will work the same way in Java. Of course this bypasses the Mapper, but it should be easy to map the results into a custom DTO that contains only the attributes you need.
val table = com.amazonaws.services.dynamodbv2.document.DynamoDB(myClient).getTable("places")
val items = table.scan(null,"id,country",null,null) // filterExpression is null
val iterator: Iterator<Item> = items.iterator()
while (iterator.hasNext()) {
log.debug(iterator.next().toJSONPretty()) // prints only id and country
}
Upvotes: 0
Reputation: 47259
Yes, the DynamoDBMapper
has support for using ProjectionExpressions with both the query
and scan
methods. I don't see any support on the load
.
Here is an example using the public <T> PaginatedQueryList<T> query(java.lang.Class<T> clazz, DynamoDBQueryExpression<T> queryExpression)
and providing a projection DynamoDBQueryExpression
. Look at the .withProjectionExpression("var1, #projectedVar")
which uses an ExpressionAttributeNames for one attribute. If you need to retrieve attributes that are not top-level attributes, you will have to look at the DocumentPaths documentation:
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.PaginatedQueryList;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.util.Tables;
import java.util.HashMap;
import java.util.Map;
public class MyTest {
public static final String TABLE_NAME = "test_table";
public static void main(String[] args) throws Exception {
final AmazonDynamoDB dynamodb =
new AmazonDynamoDBClient(new BasicAWSCredentials("aws", "key"));
dynamodb.setEndpoint("http://localhost:8000");
if (Tables.doesTableExist(dynamodb, TABLE_NAME)) {
dynamodb.deleteTable(TABLE_NAME);
}
final DynamoDBMapper mapper = new DynamoDBMapper(dynamodb);
final CreateTableRequest request = mapper.generateCreateTableRequest(MyClass.class)
.withProvisionedThroughput(new ProvisionedThroughput(5L, 5L));
dynamodb.createTable(request);
final MyClass myClass1 = new MyClass();
myClass1.setHash("H1");
myClass1.setRange("R1");
myClass1.setVar1("v1");
myClass1.setVar2("v2");
myClass1.setVar3("v3");
mapper.save(myClass1);
myClass1.setRange("R2");
myClass1.setVar1("v4");
myClass1.setVar2("v5");
myClass1.setVar3("v6");
mapper.save(myClass1);
myClass1.setRange("R3");
myClass1.setVar1("v7");
myClass1.setVar2("v8");
myClass1.setVar3("v9");
mapper.save(myClass1);
final HashMap<String, String> expressionAttributeNames = new HashMap<>();
expressionAttributeNames.put("#myHash", "hash");
expressionAttributeNames.put("#projectedVar", "var3");
final Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(":hashValue", new AttributeValue("H1"));
final DynamoDBQueryExpression<MyClass> queryExpression = new DynamoDBQueryExpression<MyClass>()
.withKeyConditionExpression("#myHash = :hashValue")
.withExpressionAttributeNames(expressionAttributeNames)
.withExpressionAttributeValues(expressionAttributeValues)
.withProjectionExpression("var1, #projectedVar");
final DynamoDBMapperConfig mapperConfig =
new DynamoDBMapperConfig(DynamoDBMapperConfig.ConsistentReads.CONSISTENT);
final PaginatedQueryList<MyClass> query = mapper.query(MyClass.class, queryExpression, mapperConfig);
query.forEach(System.out::println);
}
}
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
@DynamoDBTable(tableName = MyTest.TABLE_NAME)
public class MyClass {
private String hash;
private String range;
private String var1;
private String var2;
private String var3;
@DynamoDBHashKey
public String getHash() { return hash; }
public void setHash(String hash) { this.hash = hash; }
@DynamoDBRangeKey
public String getRange() { return range; }
public void setRange(String range) { this.range = range; }
@DynamoDBAttribute
public String getVar1() { return var1; }
public void setVar1(String var1) { this.var1 = var1; }
@DynamoDBAttribute
public String getVar2() { return var2; }
public void setVar2(String var2) { this.var2 = var2; }
@DynamoDBAttribute
public String getVar3() { return var3; }
public void setVar3(String var3) { this.var3 = var3; }
@Override
public String toString() {
return "MyClass{" +
"hash='" + hash + '\'' +
", range='" + range + '\'' +
", var1='" + var1 + '\'' +
", var2='" + var2 + '\'' +
", var3='" + var3 + '\'' +
'}';
}
}
And the output, showing that only the projected attributes are retrieved:
MyClass{hash='null', range='null', var1='v1', var2='null', var3='v3'}
MyClass{hash='null', range='null', var1='v4', var2='null', var3='v6'}
MyClass{hash='null', range='null', var1='v7', var2='null', var3='v9'}
Upvotes: 4