I am using DynamoDBMapper to scan a a table, specifically a column named "title". I should be returned a list of blogs that contains a string passed into the scanExpression. This is code I wrote about a year and a half ago which I remember working. Maybe something has been updated since?
Thanks!
public List<BlogDetailsEntity> searchBlogs(String query) {
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
scanExpression.addFilterCondition("title", new Condition()
.withComparisonOperator(ComparisonOperator.CONTAINS)
.withAttributeValueList(new AttributeValue().withS(query.toLowerCase())));
return dynamoDBMapper.scan(BlogDetailsEntity.class, scanExpression);
}
Your code is not best practice anymore. Java V1 and this mapper should be replaced with AWS SDK for Java V2.
To get the latest code for AWS, always refer to the new AWS Code Library here.
Code examples for DynamoDB using AWS SDKs
To filter a column using the V2 enhanced client (a replacement for DynamoDBMapper), you can use DynamoDbEnhancedClient. For example, assume you want to scan a table to get all Closed items on a column named archive.
You can use code like this.
// Get Open items from the DynamoDB table.
public List<WorkItem> getOpenItems() {
// Create a DynamoDbEnhancedClient.
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(getClient())
.build();
try{
// Create a DynamoDbTable object.
DynamoDbTable<Work> table = enhancedClient.table("Work", TableSchema.fromBean(Work.class));
AttributeValue attr = AttributeValue.builder()
.s("Open")
.build();
Map<String, AttributeValue> myMap = new HashMap<>();
myMap.put(":val1",attr);
Map<String, String> myExMap = new HashMap<>();
myExMap.put("#archive", "archive");
// Set the Expression so only Closed items are queried from the Work table.
Expression expression = Expression.builder()
.expressionValues(myMap)
.expressionNames(myExMap)
.expression("#archive = :val1")
.build();
ScanEnhancedRequest enhancedRequest = ScanEnhancedRequest.builder()
.filterExpression(expression)
.limit(15)
.build();
// Scan items.
Iterator<Work> results = table.scan(enhancedRequest).items().iterator();
WorkItem workItem ;
ArrayList<WorkItem> itemList = new ArrayList<>();
while (results.hasNext()) {
workItem = new WorkItem();
Work work = results.next();
workItem.setName(work.getName());
workItem.setGuide(work.getGuide());
workItem.setDescription(work.getDescription());
workItem.setStatus(work.getStatus());
workItem.setDate(work.getDate());
workItem.setId(work.getId());
// Push the workItem to the list.
itemList.add(workItem);
}
return itemList;
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
return null;
}
You can find a complete AWS end to end developer tutorial that teaches you how to use this code to display Amazon DynamoDB items in a React client app. For example, this illustration shows Closed items.
This complete doc can be found in the code lib here:
Create an Amazon Relational Database Service item tracker
Related
My goal is to retrieve all item's ids. For that, I'm gonna use Java and DynamoDBMapper.
The way to do it is to use scan. Right now, my code looks like this:
DynamoDBScanExpression paginatedScanListExpression = new DynamoDBScanExpression()
.withLimit(10000)
.withProjectionExpression("id");
var paginatedList = mapper.scanPage(MyObject.class, paginatedScanListExpression);
The problem is that I get only 600 ids per request. I'm aware of a DynamoDB 1MB per query limit, but still, it seems that 600 ids are too little for one request. Does anyone know how I can fetch all the ids more efficiently?
You can try with ScanSpec with ProjectionExpression which specifies the attributes you want in the scan result.
ScanSpec scanSpec = new ScanSpec().withProjectionExpression("id");
try {
ItemCollection<ScanOutcome> items = table.scan(scanSpec);
Iterator<Item> iter = items.iterator();
while (iter.hasNext()) {
Item item = iter.next();
System.out.println(item.toString());
}
}
catch (Exception e) {
System.err.println("Unable to scan the table:");
System.err.println(e.getMessage());
}
Reference - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.Java.04.html
Trying to run a local amazon dynamo db client with the following code which is basically just a sample i have gotten online, I have created the table with local stack so it should exist not really sure what the issue is.
public static void main(String[] args) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("attestation-db");
// Build a list of related items
List<Number> relatedItems = new ArrayList<Number>();
relatedItems.add(341);
relatedItems.add(472);
relatedItems.add(649);
//Build a map of product pictures
Map<String, String> pictures = new HashMap<String, String>();
pictures.put("FrontView", "http://example.com/products/123_front.jpg");
pictures.put("RearView", "http://example.com/products/123_rear.jpg");
pictures.put("SideView", "http://example.com/products/123_left_side.jpg");
//Build a map of product reviews
Map<String, List<String>> reviews = new HashMap<String, List<String>>();
List<String> fiveStarReviews = new ArrayList<String>();
fiveStarReviews.add("Excellent! Can't recommend it highly enough! Buy it!");
fiveStarReviews.add("Do yourself a favor and buy this");
reviews.put("FiveStar", fiveStarReviews);
List<String> oneStarReviews = new ArrayList<String>();
oneStarReviews.add("Terrible product! Do not buy this.");
reviews.put("OneStar", oneStarReviews);
// Build the item
Item item = new Item()
.withPrimaryKey("Id", 123)
.withString("Title", "Bicycle 123")
.withString("Description", "123 description")
.withString("BicycleType", "Hybrid")
.withString("Brand", "Brand-Company C")
.withNumber("Price", 500)
.withStringSet("Color", new HashSet<String>(Arrays.asList("Red", "Black")))
.withString("ProductCategory", "Bicycle")
.withBoolean("InStock", true)
.withNull("QuantityOnHand")
.withList("RelatedItems", relatedItems)
.withMap("Pictures", pictures)
.withMap("Reviews", reviews);
// Write the item to the table
PutItemOutcome outcome = table.putItem(item);
but i keep getting the following error when i run the main method.
Exception in thread "main" java.lang.NoSuchMethodError: com.amazonaws.util.StringUtils.trim(Ljava/lang/String;)Ljava/lang/String;
at com.amazonaws.auth.profile.internal.AwsProfileNameLoader.getEnvProfileName(AwsProfileNameLoader.java:72)
at com.amazonaws.auth.profile.internal.AwsProfileNameLoader.loadProfileName(AwsProfileNameLoader.java:54)
at com.amazonaws.regions.AwsProfileRegionProvider.<init>(AwsProfileRegionProvider.java:40)
at com.amazonaws.regions.DefaultAwsRegionProviderChain.<init>(DefaultAwsRegionProviderChain.java:23)
at com.amazonaws.client.builder.AwsClientBuilder.<clinit>(AwsClientBuilder.java:58)
at com.lmig.global.event.framework.sample.publisher.application.code.Attestation.main(Attestation.java:18)
It seems there are many versions of SDK present in classpath. can you try print the locations where classes are being loaded.
System.out.println(StringUtils.getClass().getProtectionDomain().getCodeSource());
System.out.println(AwsProfileNameLoader.getClass().getProtectionDomain().getCodeSource());
I created a table in Amazon dynamodb with primary key Issue(String) which has data stored in it.I want to read the values from my table. I'm using the following code..
#DynamoDBTable(tableName="Incident")
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient();
String tableName = "Incident";
Table table = dynamoDBClient.getTable("Incident");
Item getItem=dynamoDBClient.getItem();
I'm getting an error when calling the getTable method.... is it a predefined method just like createTable() or do we need to write our own..if so how?
And also what method should be used to read all items in the table..?
I used this link to write some of the code... http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/JavaDocumentAPIItemCRUD.html#JavaDocumentAPIGetItem
I'm new to Java please help..
Scan API can be used to get all the items from the table.
The scan should be done until LastEvaluatedKey is not null which is very important to get all the items. Otherwise, you will not get all the items if the table has many items i.e. the API will return 1 MB of data per scan.
A Scan operation performs eventually consistent reads by default, and
it can return up to 1 MB (one page) of data.
Scan API
Map<String, AttributeValue> lastKeyEvaluated = null;
do {
ScanRequest scanRequest = new ScanRequest()
.withTableName("ProductCatalog")
.withLimit(10)
.withExclusiveStartKey(lastKeyEvaluated);
ScanResult result = client.scan(scanRequest);
for (Map<String, AttributeValue> item : result.getItems()){
printItem(item);
}
lastKeyEvaluated = result.getLastEvaluatedKey();
} while (lastKeyEvaluated != null);
Here is example how to read data using Scan API :
#Override
protected ArrayList<String> doInBackground(String... params) {
String tableName = params[0];
ArrayList<String> tempList = new ArrayList<String>();
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient (
new BasicAWSCredentials(Constants.ACCESS_KEY_ID,
Constants.SECRET_KEY));
ScanRequest scanRequest = new ScanRequest()
.withTableName(tableName);
//.withAttributesToGet("name");
com.amazonaws.services.dynamodb.model.ScanResult result = dynamoDBClient.scan(scanRequest);
for (Map<String, AttributeValue> item : result.getItems()) {
tempList.add(item.toString());
//analizeItem(tempList, item);
}
return tempList;
}
Reference from programcreeks
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.AP_SOUTH_1).build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("Student");
Item item = table.getItem("PK", "portion Key","SK","Sort Key");
System.out.println(item.toJSONPretty());
I have a DynamoDB table with 2 attributes - a String for an ID and a JSON document. From my research I've found there is not a way to specify JSON as the type for Table.updateItem() in the Java SDK. For my update I want to overwrite the JSON document completely rather than go in an update specific attributes. I also want to do an updateItem rather than putItem (since it did seem like I could use putItem since I am just overwriting the document every time) because I will eventually have some other top-level attributes in my table that I do not want to overwrite or update every time I need to do an update - I want to be able to come in and just update the document attribute and update it completely.
I've gotten something that almost works for my CRUD operations but am wondering if there's a better way. For example I'm doing something like this:
public <T extends BaseEntity> void updateObject(T newEntity, UUID uuid) {
try {
TypeReference<HashMap<String, Object>> typeRef =
new TypeReference<HashMap<String, Object>>() {};
HashMap<String, Object> dataMap =
mapper.readValue(mapper.writeValueAsString(newEntity), typeRef);
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("Id", uuid.toString())
.withAttributeUpdate(new AttributeUpdate("data").put(dataMap))
.withReturnValues(ReturnValue.UPDATED_NEW);
UpdateItemOutcome outcome = table.updateItem(updateItemSpec);
} catch (Exception e) {}
}
I really wish I could just do something like this instead:
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("Id", uuid.toString())
.withUpdateExpression("set #da = :d")
.withNameMap(new NameMap()
.with("#da", "data"))
.withValueMap(new ValueMap()
.withJSON(":d", objectAsStr)) // withJSON() method sadly doesn't exist
.withReturnValues(ReturnValue.UPDATED_NEW);
Any help or suggestions greatly appreciated. Thanks.
Today, it seems that ValueMap.withJSON(String) method exists.
The new AWS DynamoDB document API allows 2 new data types that correspond directly to the underlying JSON representation: Map (aka JSON object) and List (aka JSON array).
However, I can't find a way to update attributes of these data types without completely overwriting them. In contrast, a Number attribute can be updated by ADDing another number, so in Java you can do something like:
new AttributeUpdate("Some numeric attribute").addNumeric(17);
Similarly you can addElements to an attribute of a Set data type. (In the old API you would use AttributeAction.ADD for both purposes.)
But for a Map or a List, it seems you must update the previous value locally, then PUT it instead of that value, for example in Java:
List<String> list = item.getList("Some list attribute");
list.add("new element");
new AttributeUpdate("Some list attribute").put(list);
This is much less readable, and under some circumstances much less efficient.
So my questions are:
Is there a way to update an attribute of a Map or a List data type without overwriting the previous value? For example, to add an element to a List, or to put an element in a Map?
How would you implement it using the Java API?
Do you know of plans to support this in the future?
Please take a look at UpdateExpression in the UpdateItem API
For example given an item with a list:
{
"hashkey": {"S" : "my_key"},
"my_list" : {"L":
[{"N":"3"},{"N":"7"} ]
}
You can update the list with code like the following:
UpdateItemRequest request = new UpdateItemRequest();
request.setTableName("myTableName");
request.setKey(Collections.singletonMap("hashkey",
new AttributeValue().withS("my_key")));
request.setUpdateExpression("list_append(:prepend_value, my_list)");
request.setExpressionAttributeValues(
Collections.singletonMap(":prepend_value",
new AttributeValue().withN("1"))
);
dynamodb.updateItem(request);`
You can also append to the list by reversing the order of the arguments in the list_append expression.
An expression like: SET user.address.zipcode = :zip would address a JSON map element combined with expression attribute values {":zip" : {"N":"12345"}}
Base on DynamoDB examples, this also work (scala)
val updateItemSpec:UpdateItemSpec = new UpdateItemSpec()
.withPrimaryKey("hashkey", my_key)
.withUpdateExpression("set my_list = list_append(:prepend_value, my_list)")
.withValueMap(new ValueMap()
.withList(":prepend_value", "1"))
.withReturnValues(ReturnValue.UPDATED_NEW)
println("Updating the item...")
val outcome: UpdateItemOutcome = table.updateItem(updateItemSpec)
println("UpdateItem succeeded:\n" + outcome.getItem.toJSONPretty)
A generic function to add or update a key/value pairs. attribute updateColumn should be of type map.
Update tableName attribute name should be passed as attributeName under key:value pairs where primaryKey = primaryKeyValue
public boolean insertKeyValue(String tableName, String primaryKey, String
primaryKeyValue, String attributeName, String newKey, String newValue) {
//Configuration to connect to DynamoDB
Table table = dynamoDB.getTable(tableName);
boolean insertAppendStatus = false;
try {
//Updates when map is already exist in the table
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey(primaryKey, primaryKeyValue)
.withReturnValues(ReturnValue.ALL_NEW)
.withUpdateExpression("set #columnName." + newKey + " = :columnValue")
.withNameMap(new NameMap().with("#columnName", attributeName))
.withValueMap(new ValueMap().with(":columnValue", newValue))
.withConditionExpression("attribute_exists("+ attributeName +")");
table.updateItem(updateItemSpec);
insertAppendStatus = true;
//Add map column when it's not exist in the table
} catch (ConditionalCheckFailedException e) {
HashMap<String, String> map = new HashMap<>();
map.put(newKey, newValue);
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey(primaryKey,primaryKeyValue)
.withReturnValues(ReturnValue.ALL_NEW)
.withUpdateExpression("set #columnName = :m")
.withNameMap(new NameMap().with("#columnName", attributeName))
.withValueMap(new ValueMap().withMap(":m", map));
table.updateItem(updateItemSpec);
insertAppendStatus = true;
} catch(Exception e) {
e.printStackTrace();
}
return insertAppendStatus;
}