I am using Dynamodb Item - getItem API to get records from DynamoDB table. But it returns Item object and I want to retrieve specific attribute value from the Item object. How can we do it in Java? I couldn't find references.
Table table = dynamoDB.getTable(tableName);
Item item = table.getItem(hashKeyFieldName, hashKeyFieldValue);
The item contains the following fields:
HashKey, TimeStamp, NumRetries
I want to get the specific NumRetries value from item above. Is it something that is possible? something like int numRetries = item.get("NumRetries");?
You should be able to do that with a Projection Expression:
GetItemSpec spec = new GetItemSpec().withPrimaryKey("primaryKey", primaryKey)
.withProjectionExpression("HashKey, TimeStamp, NumRetries");
Item outcome = table.getItem(spec);
A names map may be necessary.
You can use Projection Expressions to get certain attributes from an item but do keep in mind that using projection expressions does not reduce the usage and cost of RCUs that are used in retrieving the object.
Code example,
GetItemSpec spec = new GetItemSpec()
.withPrimaryKey("YourPrimaryKey", value)
.withProjectionExpression("NumRetries");
Item item = table.getItem(spec);
System.out.println(item.toJSONPretty());
More code examples can be found here.
Related
I've seen a lot of examples of using UpdateExpression to update attributes using the updateItem method. However, I still don't understand how to update multiple attributes in DynamoDB at the same time dynamically.
I am trying to update AND rename multiple attributes in the same updateItem call.
I understand that this requires a REMOVE of the old name and a SET of the new name. I have these names in hashedId's of objects, but won't have them until runtime. So my question is how do I use UpdateExpression with variables and not a hard-coded String?
All the examples I have seen use hard-coded UpdateExpressions.
can't update item in DynamoDB
Dynamo DB : UpdateItemSpec : Multiple Update Expression - Not Working
DynamoDB update Item multi action
How to rename DynamoDB column/key
I am working in Java.
It seems very odd to me that I haven't been able to find an example of this... which leads me to believe I am doing something wrong.
Thanks for the help!
You have to build the update expression string dynamically based on the attribute names and values that you receive at runtime. I do exactly this. I'm not working in Java, but here is some pseudo code (with a Ruby bias) example for you that dynamically builds the update expression string, the expression attribute names hash, and the expression attribute values hash. You can then plug in these 3 things into the update_item method:
update_exp_set = [] //array of remove expression snippets
update_exp_remove = [] //array of update expression snippets
exp_attribute_names = {} //hash of attribute names
exp_attribute_values = {} //hash of attribute values
// Iterate through all your fields and add things as needed to your arrays and hashes.
// Two examples are below for a field with the name <fieldName> and value <fieldValue>.
// You'll need to convert this to Java and update it to make sense with the AWS Java SDK.
// For a given field that needs to be updated:
update_exp_set << "#<fieldName> = :fieldValue" //add to array of set expression snippets
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
exp_attribute_values[":<fieldValue>"] = "<fieldValue>" //add to hash of attribute values
// For a given field that needs to be removed:
update_exp_remove << "#<fieldName>"
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
// Use your snippets to create your full update expression:
update_exp_set_clause = ""
update_exp_remove_clause = ""
if update_exp_set.length != 0 //check if you have something to set
update_exp_set_clause = "SET " + update_exp_set.join(',')
end
if update_exp_remove.length != 0 //check if you have something to remove
update_exp_remove_clause = "REMOVE" + update_exp_remove.join(',')
end
final_update_exp = update_exp_set_clause + " " + update_exp_remove_clause
Does this help?
I have a list of objects which I want to insert into a collection. The mongoTemplate.insert(list); works fine but now I want to modify it to upsert(); as my list can contain duplicate objects which are already inserted into a collection. So what I want is insert entire list and on the go check if the item is already present in the collection then skip it else insert it.
You can try out continueOnError or ordered flag like this:
db.collection.insert(myArray, {continueOnError: true})
OR,
db.collection.insert(myArray, {ordered: false})
You need to create a unique index field of your object's id(if there is no unique constraint). So that it will make error while you try to insert using same id.
Using the unique constraint you insert array or using BulkInsert
For using insert you can set a flag continueOnError: true which can continue insertion whenever error found in case of error because of unique constraint while inserting existing id of object.
The only way to do a bulk-upsert operation is the method MongoCollection.bulkWrite (or at least: the only way I know... ;-))
To use it, you have to convert your documents to the appropriate WriteModel: for upserts on a per-document basis, this is UpdateOneModel.
List<Document> toUpdate = ...;
MongoCollection coll = ...;
// Convert Document to UpdateOneModel<Document>
List<UpdateOneModel<Document>> bulkOperationList = toUpdate.stream()
.map(doc -> new UpdateOneModel<Document>(
Filters.eq("_id", doc.get("_id")), // identify by same _id
doc,
new UpdateOptions().upsert(true)))
.collect(Collectors.toList());
// Write to DB
coll.bulkWrite(bulkOperationList);
(Disclaimer: I only typed this code, I never ran it)
I want to update an item in DynamoDB only if the new item has a more recent date than the existing item. Currently, I'm querying for the existing item, doing the comparison in my code, and then writing to db. I was wondering if there was a way to have DynamoDB do the checking for me. I've looked into using Expected, but its comparison operators need to take in a parameter, which defeats the purpose since it means having to query for the existing item anyway.
I'm working with Java 8.
The ConditionExpression can be used to check the condition and update the item if the condition is satisfied. This is similar to the WHERE condition in the SQL statement. The differences are:-
1) DynamoDB requires both Partition key and Range key to update the item. The non key attribute conditions can be given in the ConditionExpression
2) DynamoDB can update only one item at a time.
ConditionExpression — (String) A condition that must be satisfied in
order for a conditional update to succeed.
Expected — (map) This is a legacy parameter, for backward
compatibility. New applications should use ConditionExpression
instead. Do not combine legacy parameters and expression parameters in
a single API call; otherwise, DynamoDB will return a
ValidationException exception.
Sample code:-
The below code updates the item only if existing value "createdate" attribute is less than the new value (i.e. in other words new value is greater than the existing value in the table).
UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("yearkey", yearKey, "title", title)
.withReturnValues(ReturnValue.UPDATED_NEW).withUpdateExpression("set #createdate = :val1")
.withNameMap(new NameMap().with("#createdate", "createdate"))
.withValueMap(new ValueMap().withString(":val1", createDate))
.withConditionExpression("createdate < :val1");
UpdateItemOutcome outcome = null;
try {
outcome = table.updateItem(updateItemSpec);
} catch (ConditionalCheckFailedException ce) {
System.out.println("Conditional check failed." + ce.getMessage());
return false;
}
return true;
EDIT:
I was actually incorrect. I was querying the table when I meant to query an index which explains my error. Vikdor's solution is a valid one though.
ORIGINAL:
I have a table with a Hash-Range key schema in DynamoDB. I need to be able to get all items associated with a specific hash key but it seems to require a range key condition. My issue is I want EVERY range key but there is no wildcard option. As of right now my range key is a string and the only way I could think to do this is by querying all range keys greater or equal to the smallest ascii characters I can use since the documentation says it sorts based on ascii character values.
I looked into scanning but it appears that simply will read the entire table which is NOT an option.
Is there any better way to query for all values of a hash key or can anyone confirm that using the method with the ascii character will work?
but it seems to require a range key condition.
This doesn't sound to be true.
I use DynamoDBMapper and use DynamoDBQueryExpression to query all the records with a given HashKey as follows:
DynamoDBQueryExpression<DomainObject> query =
new DynamoDBQueryExpression<DomainObject>();
DomainObject hashKeyValues = new DomainObject();
hashKeyValues.setHashKey(hashKeyValue);
query.setHashKeyValues(hashKeyValues);
// getMapper() returns a DynamoDBMapper object with the appropriate
// AmazonDynamoDBClient object.
List<DomainObject> results = getMapper().query(query);
HTH.
You can use DynamoDB's query API, which allows you to query the database based conditional expressions using the hash/range keys. You can see examples of the API here. Here is a relevant example:
ItemCollection<QueryOutcome> items = table.query("theHashFieldName", "theHashFieldToQuery");
You can also query using more complex expressions. E.g.:
DynamoDB dynamoDB = new DynamoDB(
new AmazonDynamoDBClient(new ProfileCredentialsProvider()));
Table table = dynamoDB.getTable("TableName");
QuerySpec spec = new QuerySpec()
.withKeyConditionExpression("Id = :v_id")
.withValueMap(new ValueMap()
.withString(":v_id", "TheId"));
ItemCollection<QueryOutcome> items = table.query(spec);
Iterator<Item> iterator = items.iterator();
Item item = null;
while (iterator.hasNext()) {
item = iterator.next();
System.out.println(item.toJSONPretty());
}
I am using Google trends to get trends for particulate keyword. it will returning JSON but main problem is that i want to create class that holds data and used in java code as array List.
I am confused what is the class structure for it when i get result look like below
{"version":"0.6","status":"ok","sig":"1248242565",
"table":
{ "cols":
[{"id":"date","label":"Date","type":"date","pattern":""},
{"id":"query0","label":"linkedin","type":"number","pattern":""},
{"id":"query1","label":"facebook","type":"number","pattern":""}],
"rows":[{"c":[{"v":new Date(2004,0,1),"f":"January 2004"},{"v":0.0,"f":"0"},{"v":0.0,"f":"0"}]},
{"c":[{"v":new Date(2004,5,1),"f":"June 2004"},{"v":0.0,"f":"0"}, {"v":0.0,"f":"0"}]},
{"c":[{"v":new Date(2004,8,1),"f":"September 2004"},{"v":0.0,"f":"0"},{"v":0.0,"f":"0"}]},
{"c":[{"v":new Date(2013,9,1),"f":"October 2013"},{"v":1.0,"f":"1"},{"v":83.0,"f":"83"}]}]
}
}
It will return row and cols on search query if i search two individual word the the result is like above JSON. nay idea to how can i can make class Trend.java and that list object that holds all this informations
How would you represent those values? I'd go for a List<HashMap<String, String>> implementation.
You can assign each item in a row to a HashMap with the column header as the key. So:
HashMap<String, String> row = new HashMap<String, String>();
row.put("id", "c");
// add the rest.
Then you can cycle through each row, and request the column data by name. This will also make for some very semantically nice code!