Front-End Web & Mobile
Amazon DynamoDB on Mobile – Part 3: Writing Data
Version 2 of the AWS Mobile SDK
- This article and sample apply to Version 1 of the AWS Mobile SDK. If you are building new apps, we recommend you use Version 2. For details, please visit the AWS Mobile SDK page.
- This content is being maintained for historical reference.
In our previous posts (Part 1, Part 2), we discussed how we can read data from an Amazon DynamoDB table using the AWS Mobile SDKs. In this post, we will discuss our options for writing data to DynamoDB.
Creating/Updating a Record
If we want to write a record in our table, we can use the PutItem
API action and supply the full item we wish to write. Other than respecting the schema for our key (number for UserId
, string for RecordId
), we can use any value type we so choose for any other attribute in the item, mixing and matching types however we choose.
iOS
// create the request, specify the table DynamoDBPutItemRequest *putItemRequest = [DynamoDBPutItemRequest new]; request.tableName = @"UserTableExample"; // Each attribute will be a DynamoDBAttributeValue DynamoDBAttributeValue *value = [[DynamoDBAttributeValue alloc] initWithN:@"1234"]; [request.item setValue:value forKey:@"UserId"]; // The item is an NSMutableDictionary, keyed by the attribute name value = [[DynamoDBAttributeValue alloc] initWithS:@"FavoriteColors"]; [request.item setValue:value forKey:@"RecordId"]; // Now that we've added our required key attributes, // we can add anything else we choose, even a set of strings value = [DynamoDBAttributeValue new]; [value addSS:@"Green"]; [value addSS:@"Red"]; [value addSS:@"Black"]; [request.item setValue:value forKey:@"Data"]; // process the request DynamoDBPutItemResponse *response = [self.ddb putItem:request];
Android
// Each attribute will be an AttributeValue Map<String,AttributeValue> item = new HashMap<String, AttributeValue>(); item.put("UserId", new AttributeValue().withN("1234")); item.put("RecordId", new AttributeValue().withS("FavoriteColors")); // Now that we've added our required key attributes, // we can add anything else we choose, even a set of strings item.put("Data", new AttributeValue().withSS("Green", "Red", "Black")); // Construct our request, supply table name PutItemRequest putItemRequest = new PutItemRequest("UserTableExample", item); // process the request PutItemResult putItemResult = ddbClient.putItem(putItemRequest);
As we saw with our read requests in Part 2, we can optionally receive information about our consumed capacity units for our PutItem
calls.
iOS
// Ask for our total consumed capacity putItemRequest.returnConsumedCapacity = @"TOTAL"; // Execute the request DynamoDBPutItemResponse *putItemResponse = [self.ddb putItem:putItemRequest]; // Log our consumed write capacity (implied casting down to int) NSLog(@"Consumed write capacity for putItem: %d", [putItemResponse.consumedCapacity.capacityUnits integerValue]);
Android
// Ask for our total consumed capacity putItemRequest.setReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL); // Execute the request PuttItemResult result = ddbClient.putItem(putItemRequest); // Log our consumed capacity (casting to int for whole number) Log.i(LOG_TAG, "Consumed write capacity for putItem: = " + result.getConsumedCapacity().getCapacityUnits().intValue());
PutItem
can be used for both inserting new data and updating existing data. DynamoDB also supports an UpdateItem
where only modified records need to be supplied, but as our schema is rather small, it is not applicable to our use case.
Conditional Writes
PutItem
will insert a new item or overwrite an existing item if it exists. If we want to ensure that our record is new, we can optionally pass an ExpectedAttributeValue
to ensure the given key value doesn’t exist.
iOS
DynamoDBExpectedAttributeValue *checkExists = [DynamoDBExpectedAttributeValue new]; checkExists.exists = NO; [putItemRequest.expected setValue:checkExists forKey:@"RecordId"];
Android
Map<String,ExpectedAttributeValue> expected = new HashMap<String,ExpectedAttributeValue>(); expected.put("RecordId", new ExpectedAttributeValue().withExists(false)); putItemRequest.setExpected(expected);
Additionally, if we want to ensure that we only update a given record if it was in a known state beforehand, we can specify that expected state, also via an ExpectedAttributeValue
. This could be used to implement an atomic counter, perhaps for a number of plays in our game.
iOS
// construct our request DynamoDBPutItemRequest *putItemRequest = [DynamoDBPutItemRequest new]; request.tableName = @"UserTableExample"; DynamoDBAttributeValue *value = [[DynamoDBAttributeValue alloc] initWithN:@"1234"]; [putItemRequest.item setValue:value forKey:@"UserId"]; value = [[DynamoDBAttributeValue alloc] initWithS:@"Plays"]; [putItemRequest.item setValue:value forKey:@"RecordId"]; value = [[DynamoDBAttributeValue alloc] initWithN:@"101"]; [putItemRequest.item setValue:value forKey:@"Data"]; // Our expected attribute value also uses a DynamoDBAttributeValue // We expect it to be 100 (one less than the value we're incrementing to) value = [[DynamoDBAttributeValue alloc] initWithN:@"100"]; DynamoDBExpectedAttributeValue *attr = [[DynamoDBExpectedAttributeValue alloc] initWithValue:value]; // Add the expected value to our dictionary of expected values [putItemRequest.expected setValue:checkExists forKey:@"Data"]; // process the request DynamoDBPutItemResponse *putItemResponse = [self.ddb putItem:putItemRequest];
Android
// construct our request Map<String,AttributeValue> item = new HashMap<String, AttributeValue>(); item.put("UserId", new AttributeValue().withN("1234")); item.put("RecordId", new AttributeValue().withS("Plays")); item.put("Data", new AttributeValue().withN("101")); PutItemRequest putItemRequest = new PutItemRequest("UserTableExample", item); // Our expected attribute value also uses a AttributeValue // We expect it to be 100 (one less than the value we're incrementing to) AttributeValue counter = new AttributeValue().withN("100"); Map<String,ExpectedAttributeValue> expected = new HashMap<String,ExpectedAttributeValue>(); expected.put("Data", new ExpectedAttributeValue().withValue(counter)); putItemRequest.setExpected(expected); // process the request PutItemResult putItemResult = ddbClient.putItem(putItemRequest);
If the conditional write fails, an exception will be thrown on Android, and an NSError
or NSException
will be generated on iOS (see our previous post on how to disable exceptions in the iOS SDK). Our code should be updated to handle the failure and retry the update.
iOS
// process the request DynamoDBPutItemResponse *putItemResponse = [self.ddb putItem:putItemRequest]; // Exceptions have been disabled, so our response may contain an error if (nil != putItemReponse.error) { NSString *errorCode = [response.error.userInfo objectForKey:@"errorCode"]; if ([errorCode isEqualToString:@"ConditionalCheckFailedException"]) { // our conditional update failed, fetch item from DynamoDB // to get current value and update request to retry ... } else { // some other class of error occurred ... } }
Android
try { // process the request PutItemResult putItemResult = ddbClient.putItem(putItemRequest); } catch (ConditionalCheckFailedException error) { // our conditional update failed, fetch item from DynamoDB // to get current value and update request to retry ... } catch (AmazonServiceException error) { // some other class of error occurred ... }
For more information about conditional writes, please refer to the Amazon DynamoDB Developer Guide.
Deleting an Item
If we want to delete a record from our table, we can use the DeleteItem
API action, which only requires that we pass the key of the item we wish to delete.
iOS
// create our request DynamoDBDeleteItemRequest *deleteItemRequest = [DynamoDBDeleteItemRequest new]; request.tableName = @"UserTableExample"; // Need to specify the key of our item, which is an NSDictionary of our primary key attribute(s) DynamoDBAttributeValue *value = [[DynamoDBAttributeValue alloc] initWithN:@"1234"]; [deleteItemRequest.key setValue:value forKey:@"UserId"]; value = [[DynamoDBAttributeValue alloc] initWithS:@"FavoriteColors"]; [deleteItemRequest.key setValue:value forKey:@"RecordId"]; DynamoDBDeleteItemResponse *deleteItemResponse = [self.ddb deleteItem:deleteItemRequest];
Android
// Need to specify the key of our item, which is a Map of our primary key attribute(s) Map<String,AttributeValue> key = new HashMap<String,AttributeValue>(); key.put("UserId", new AttributeValue().withN("1234")); key.put("RecordId", new AttributeValue().withS("FavoriteColors")); // create our request DeleteItemRequest deleteItemRequest = new DeleteItemRequest("UserTableExample", key); // process our request DeleteItemResult deleteItemResponse = ddbClient.deleteItem(deleteItemRequest);
We hope this illustrates the basics of writing and modifying data to DynamoDB with the AWS Mobile SDKs. Please stay tuned for the final post in this series where we discuss some of the latest enhancements to Amazon DynamoDB and how you can use them in your mobile apps.
The code samples included in this post are for the DynamoDB API version 2012-08-10 and will work only with the AWSDynamoDB.framework
on iOS and the com.amazonaws.services.dynamodbv2
package on Android. See our previous post on how to convert your iOS application to use the new service level frameworks.