I have dynamodb table structure as follows:
{
"id": "1",
"skills": {
"skill1": "html",
"skill2": "css"
}
}
I have task to filter by skills value, In order to complete my task wrote java logic as follows:
AmazonDynamoDB client = dynamoDBService.getClient();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("dummy");
Map<String, String> attributeNames = new HashMap<String, String >();
attributeNames.put("#columnValue", "skills.skill1");
Map<String, AttributeValue> attributeValues = new HashMap<String, AttributeValue>();
attributeValues.put(":val1", new AttributeValue().withS("html"));
ScanSpec scanSpec = new ScanSpec().withProjectionExpression("skills.skill1")
.withFilterExpression("#columnValue = :val1 ").withNameMap(new NameMap().with("#columnValue", "skills.skill1"))
.withValueMap(new ValueMap().withString(":val1", "html"));
ItemCollection<ScanOutcome> items = table.scan(scanSpec);
Iterator<Item> iter = items.iterator();
while (iter.hasNext()) {
Item item = iter.next();
System.out.println("--------"+item.toString());
}
The mentioned code does not help me out. Any solution ?
You can use a ProjectionExpression to retrieve only specific attributes or elements, rather than an entire item. A ProjectionExpression can specify top-level or nested attributes, using document paths.
for example from AWS:
GetItemSpec spec = new GetItemSpec()
.withPrimaryKey("Id", 206)
.withProjectionExpression("Id, Title, RelatedItems[0], Reviews.FiveStar")
.withConsistentRead(true);
Item item = table.getItem(spec);
System.out.println(item.toJSONPretty());
Simple solution to this problem is:
First fetch all the records from the table.
Then iterate over the list of that object.
Extract the skills from each object.
Wrote your logic to do filtering.
Repeat the loop till the last record.
I found solution,scanSpec should be as follows:
ScanSpec scanSpec = new ScanSpec()
.withFilterExpression("#category.#uid = :categoryuid").withNameMap(new NameMap().with("#category","skills").with("#uid",queryString))
.withValueMap(new ValueMap().withString(":categoryuid", queryString));
Related
In a DynamoDB table where CustomerStatus is a column in which item may contain 'Active','Inactive' or 'Deleted' as CustomerStatus. I want to fetch all customers whose status is 'Active' as well 'Inactive'.
Here is the code sample I am using, but I am not sure how to get it done.
private Object data(MuleEventContext eventContext) {
List<Object> finalJson = new ArrayList<Object>();
String tableName = "Customers";
NameMap nameMap = new NameMap();
nameMap.put("#v_status", "CustomerStatus");
ValueMap valueMap = new ValueMap();
valueMap.put(":v_statusval", "Deleted");
BasicAWSCredentials cre = new BasicAWSCredentials(accesKey,secretKey);
AmazonDynamoDB dynamoDB1 = AmazonDynamoDBClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(cre)).withRegion(Regions.EU_WEST_1).build();
DynamoDB dynamoDB = new DynamoDB(dynamoDB1);
Table table = dynamoDB.getTable(tableName);
QuerySpec querySpec = new QuerySpec().withKeyConditionExpression("#v_status != :v_statusval")
.withNameMap(nameMap)
.withValueMap(valueMap);
ItemCollection<QueryOutcome> items = null;
Iterator<Item> iterator = null;
Item item = null;
try {
items = table.query(querySpec);
iterator = items.iterator();
while (iterator.hasNext()) {
item = iterator.next();
finalJson.add(item.asMap());
}
} catch (Exception e) {
logger.info(e.getMessage());
}
return finalJson;
}
You can't filter on a HASH key.
I would need to know which attribute is the HASH key and which is the RANGE key.
If the CustomerStatus is not the HASH key, the best way is to create a secondary index for this attribute and do 2 different queries:
One for the Active;
Another one for the Inactive.
This is the most efficient way to do this kind of query.
Another way is doing a scan and filtering the attribute, using the IN operand, as stated in Syntax for Condition Expressions. But this will read all data from your table, can be slow, and consume a lot capacity.
I have a dynamodb Table and I want to do a conditional update operation on that using aws sdk java library. I have the table with hashkey named as "Id" and sortkey named as "Sk" . I have 5 other fields in the table and i have to update 2 fields based on the condition on the remaining fields. The condition is "total_record_count = record_passed + records_failed" , where total_record_count, record_passed and records_failed are the fields in the table.
Below is the code
DynamoDB dynamoDB = new DynamoDB(amazonDynamoDB);
Table table = dynamoDB.getTable("ciw_ocrResponse_upload");
Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#updatedAt", "updatedAt");
expressionAttributeNames.put("#statusOfTracker","statusOfTracker");
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Map<String, Object> eav = new HashMap<>();
eav.put(":val1", value);
eav.put(":val2", timestamp.getTime());
UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", requestId, "Sk", sortKey)
.withUpdateExpression("set #updatedAt = :val2, #statusOfTracker = :val1")
.withValueMap(eav)
.withNameMap(expressionAttributeNames)
.withConditionExpression(" total_record_count = record_passed + records_failed")
.withReturnValues(ReturnValue.UPDATED_NEW);
table.updateItem(updateItemSpec);
I am getting the error as Invalid ConditionExpression: Syntax error; token: "+", near: "record_passed + records_failed"
According to the docs this arithmetic operation is not supported.
Workaround is to create a total_record_count field which you need to calculate and add on every new item created. Also to add it to all existing items.
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 read the following link that explains to use placeholders by means of expression attribute name
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ExpressionPlaceholders.html#ExpressionAttributeValues
My json document is stored as follows:
{"user_json": {"profile.title":"abc"} }"
my java code is as follows
Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#u1", "user_json.profile.title");
String projectionExpression = "user_id, #u1";
QuerySpec spec = new QuerySpec()
.withProjectionExpression(projectionExpression)
.withKeyConditionExpression("user_id = :v_id")
.withNameMap(expressionAttributeNames)
.withValueMap(new ValueMap()
.withString(":v_id", userId))
.withConsistentRead(true);
ItemCollection<QueryOutcome> items = table.query(spec);
Iterator<Item> iterator = items.iterator();
String jsonPretty="";
while (iterator.hasNext()) {
jsonPretty = iterator.next().toJSON();
System.out.println(jsonPretty);
}
Problem: not able to retrieve Document path which has a dot in it.
can someone please point out the problem? thanks
Try doing like this:
Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#u1_1", "user_json");
expressionAttributeNames.put("#u1_2", "profile.title");
String projectionExpression = "user_id, #u1_1.#u1_2";
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;
}