Menu
AWS Mobile
Developer Guide

Integrate Your Existing NoSQL Table

Just Getting Started?

Use streamlined steps to install the SDK and integrate features.

The Get Started section of this guide allows you to create new resources and complete the steps described on this page in minutes. If you want to import existing resources or create them from scratch, the contents of this page will walk you through the steps you need.

The following steps and examples are based on a simple bookstore app. The app tracks the books that are available in the bookstore using an Amazon DynamoDB table.

Set up Your Backend

To manually configure an Amazon DynamoDB table that you can integrate into your mobile app, use the following steps.

Create an New Table and Index

To create the Books table:

  1. Sign in to the Amazon DynamoDB Console.

  2. Choose Create Table.

  3. Type Books as the name of the table.

  4. Enter ISBN in the Partition key field of the Primary key with String as their type.

  5. Check the Add sort key box , then type Category in the provided field and select String as the type.

  6. Clear the Use default settings checkbox and choose + Add Index.

  7. In the Add Index dialog type Author with String as the type.

  8. Check the Add sort key checkbox and enter Title as the sort key value, with String as its type.

  9. Leave the other values at their defaults. Choose Add index to add the Author-Title-index index.

  10. Set the Minimum provisioned capacity for read to 10, and for write to 5.

  11. Choose Create.Amazon DynamoDB will create your database.

  12. Refresh the console and choose your Books table from the list of tables.

  13. Open the Overview tab and copy or note the Amazon Resource Name (ARN). You need this for the next procedure.

Set Up an Identity Pool

To give your users permissions to access your table you'll need an identity pool from Amazon Cognito. That pool has two default IAM roles, one for guest (unauthenticated), and one for signed-in (authenticated) users. The policies you design and attach to the IAM roles determine what each type of user can and cannot do.

Import an existing pool or create a new pool for your app.

Set Permissions

Attach the following IAM policy to the unauthenticated role for your identity pool. It allows the user to perform the actions on two resources (a table and an index) identified by the ARN of your Amazon DynamoDB table.

{ "Statement": [{ "Effect": "Allow", "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Scan", "dynamodb:Query", "dynamodb:UpdateItem", "dynamodb:BatchWriteItem" ], "Resource": [ "arn:aws:dynamodb:us-west-2:123456789012:table/Books", "arn:aws:dynamodb:us-west-2:123456789012:table/Books/index/*" ] }] }

Apply Permissions

Apply this policy to the unauthenticated role assigned to your Amazon Cognito identity pool, replacing the Resource values with the correct ARN for the Amazon DynamoDB table:

  1. Sign in to the IAM console.

  2. Choose Roles and then choose the "Unauth" role that Amazon Cognito created for you.

  3. Choose Attach Role Policy.

  4. Choose Custom Policy and then Choose Select.

  5. Type a name for your policy and paste in the policy document shown above, replacing the Resource values with the ARNs for your table and index. (You can retrieve the table ARN from the Details tab of the database; then append /index/* to obtain the value for the index ARN.

  6. Choose Apply Policy.

Connect to Your Backend

Create Your AWS Configuration File

Your app is connected to your AWS resources using an awsconfiguration.json file which contains the endpoints for the services you use.

  1. Create a file with name awsconfiguration.json with the following contents:

    { "Version": "1.0", "CredentialsProvider": { "CognitoIdentity": { "Default": { "PoolId": "COGNITO-IDENTITY-POOL-ID", "Region": "COGNITO-IDENTITY-POOL-REGION" } } }, "IdentityManager": { "Default": {} }, "DynamoDBObjectMapper": { "Default": { "Region": "DYNAMODB-REGION" } } }
  2. Make the following changes to the configuration file.

    • Replace the DYNAMODB-REGION with the region the table was created in.

      Need to find your table's region?

      Go to Amazon DynamoDB Console. and choose the Overview tab for your table. The Amazon Resource Name (ARN) item shows the table's ID, which contains its region.

      For example, if your pool ID is arn:aws:dynamodb:us-east-1:012345678901:table/nosqltest-mobilehub-012345678-Books, then your the table's region value would be us-east-1.

      The configuration file value you want is in the form of: "Region": "REGION-OF-YOU-DYNAMODB-ARN". For this example:

      "Region": "us-east-1"
    • Replace the COGNITO-IDENTITY-POOL-ID with the identity pool ID.

    • Replace the COGNITO-IDENTITY-POOL-REGION with the region the identity pool was created in.

      Need to find your pool's ID and region?

      Go to Amazon Cognito Console and choose Manage Federated Identities, then choose your pool and choose Edit identity pool. Copy the value of Identity pool ID.

      Insert this region value into the following form to create the value you need for this integration.

      "Region": "REGION-PREFIX-OF-YOUR-POOL-ID".

      For example, if your pool ID is us-east-1:01234567-yyyy-0123-xxxx-012345678901, then your integration region value would be:

      "Region": "us-east-1"

Add the AWS Config File

To make the connection between your app and your backend services, add the configuration file.

Android - JavaAndroid - KotliniOS - Swift
Android - Java

In the Android Studio Project Navigator, right-click your app's res folder, and then choose New > Directory. Type raw as the directory name and then choose OK.


                        Image of creating a raw directory in Android Studio.

Drag the awsconfiguration.json you created into the res/raw folder. Android gives a resource ID to any arbitrary file placed in this folder, making it easy to reference in the app.

Android - Kotlin

In the Android Studio Project Navigator, right-click your app's res folder, and then choose New > Directory. Type raw as the directory name and then choose OK.


                        Image of creating a raw directory in Android Studio.

Drag the awsconfiguration.json you created into the res/raw folder. Android gives a resource ID to any arbitrary file placed in this folder, making it easy to reference in the app.

iOS - Swift

Drag the awsconfiguration.json into the folder containing your Info.plist file in your Xcode project. Choose Copy items and Create groups in the options dialog.

Add the SDK to your App

Use the following steps to add AWS Mobile NoSQL Database to your app.

Android - JavaAndroid - KotliniOS - Swift
Android - Java
  1. Set up AWS Mobile SDK components with the following Set Up Your Backend steps.

    1. app/build.gradle must contain:

      dependencies{ // Amazon Cognito dependencies for user access to AWS resources implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.6.+@aar') { transitive = true } // AmazonDynamoDB dependencies for NoSQL Database implementation 'com.amazonaws:aws-android-sdk-ddb-mapper:2.6.+' // other dependencies . . . }
    2. Add the following permissions to AndroidManifest.xml.

      <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  2. Create an AWSDynamoDBMapper client in the call back of your call to instantiate AWSMobileClient. This will ensure that the AWS credentials needed to connect to Amazon DynamoDB are available, and is typically in onCreate function of of your start up activity.

    import com.amazonaws.mobile.client.AWSMobileClient; import com.amazonaws.mobile.client.AWSStartupHandler; import com.amazonaws.mobile.client.AWSStartupResult; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; public class MainActivity extends AppCompatActivity { // Declare a DynamoDBMapper object DynamoDBMapper dynamoDBMapper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // AWSMobileClient enables AWS user credentials to access your table AWSMobileClient.getInstance().initialize(this, new AWSStartupHandler() { @Override public void onComplete(AWSStartupResult awsStartupResult) { // Add code to instantiate a AmazonDynamoDBClient AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(AWSMobileClient.getInstance().getCredentialsProvider()); this.dynamoDBMapper = DynamoDBMapper.builder() .dynamoDBClient(dynamoDBClient) .awsConfiguration( AWSMobileClient.getInstance().getConfiguration()) .build(); } }).execute(); // Other functions in onCreate . . . } }

Important

Use Asynchronous Calls to DynamoDB

Since calls to DynamoDB are synchronous, they don't belong on your UI thread. Use an asynchronous method like the Runnable wrapper to call DynamoDBObjectMapper in a separate thread.

Runnable runnable = new Runnable() { public void run() { //DynamoDB calls go here } }; Thread mythread = new Thread(runnable); mythread.start();
Android - Kotlin
  1. Set up AWS Mobile SDK components with the following Set Up Your Backend steps.

    1. app/build.gradle must contain:

      dependencies{ // Amazon Cognito dependencies for user access to AWS resources implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.6.+@aar') { transitive = true } // AmazonDynamoDB dependencies for NoSQL Database implementation 'com.amazonaws:aws-android-sdk-ddb-mapper:2.6.+' // other dependencies . . . }
    2. Add the following permissions to AndroidManifest.xml.

      <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  2. Create an AWSDynamoDBMapper client in the call back of your call to instantiate AWSMobileClient. This will ensure that the AWS credentials needed to connect to Amazon DynamoDB are available, and is typically in onCreate function of of your start up activity.

    import com.amazonaws.mobile.client.AWSMobileClient; import com.amazonaws.mobile.client.AWSStartupHandler; import com.amazonaws.mobile.client.AWSStartupResult; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; class MainActivity : AppCompatActivity() { var ddbMapper: DynamoDBMapper? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) AWSMobileClient.getInstance().initialize(this, object : AWSStartupHandler() { override fun onComplete(awsStartupResult: AWSStartupResult) { val ddbClient = AmazonDynamoDBClient(AWSMobileClient.getInstance().credentialsProvider) ddbMapper = DynamoDBMapper.builder() .dynamoDBClient(ddbClient) .awsConfiguration(AWSMobileClient.getInstance().configuration) .build() } }).execute() // other setup within onCreate() ... } }

Important

Use Asynchronous Calls to DynamoDB

Since calls to DynamoDB are synchronous, they don't belong on your UI thread. Use an asynchronous method like the thread wrapper to call DynamoDBObjectMapper in a separate thread.

thread(start = true ) { // DynamoDB calls go here }
iOS - Swift
  1. Set up AWS Mobile SDK components with the following Set Up Your Backend steps.

    1. Add the AWSDynamoDB pod to your Podfile to install the AWS Mobile SDK.

      platform :ios, '9.0' target :'YOUR-APP-NAME' do use_frameworks! # Enable AWS user credentials pod 'AWSMobileClient', '~> 2.6.13' # Connect to NoSQL database tables pod 'AWSDynamoDB', '~> 2.6.13' # other pods . . . end

      Run pod install --repo-update before you continue.

      If you encounter an error message that begins "[!] Failed to connect to GitHub to update the CocoaPods/Specs . . .", and your internet connectivity is working, you may need to update openssl and Ruby.

    2. Classes that call DynamoDB APIs must use the following import statements:

      import AWSCore import AWSDynamoDB

Add Data Models to Your App

To connect your app to your table create a data model object in the following form. In this example, the model is based on the Books table you created in a previous step. The partition key (hash key) is called ISBN and the sort key (rangekey) is called Category.

Android - JavaAndroid - KotliniOS - Swift
Android - Java

In the Android Studio project explorer right-click the folder containing your main activity, and choose New > Java Class. Type the Name you will use to refer to your data model. In this example the name would be BooksDO. Add code in the following form.

package com.amazonaws.models.nosql; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBAttribute; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBHashKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBIndexHashKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBIndexRangeKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBRangeKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBTable; import java.util.List; import java.util.Map; import java.util.Set; @DynamoDBTable(tableName = "Books") public class BooksDO { private String _isbn; private String _category; private String _title; private String _author; @DynamoDBHashKey(attributeName = "ISBN") @DynamoDBAttribute(attributeName = "ISBN") public String getIsbn() { return _isbn; } public void setIsbn(final String _isbn) { this._isbn = _isbn; } @DynamoDBRangeKey (attributeName = "Category") @DynamoDBAttribute(attributeName = "Category") public String getCategory() { return _category; } public void setCategory(final String _category) { this._category= _category; } @DynamoDBIndexHashKey(attributeName = "Author", globalSecondaryIndexName = "Author") public String getAuthor() { return _author; } public void setAuthor(final String _author) { this._author = _author; } @DynamoDBIndexRangeKey(attributeName = "Title", globalSecondaryIndexName = "Title") public String getTitle() { return _title; } public void setTitle(final String _title) { this._title = _title; } }
Android - Kotlin

In the Android Studio project explorer right-click the folder containing your main activity, and choose New > Java Class. Type the Name you will use to refer to your data model. In this example the name would be BooksDO. Add code in the following form. You can also use a data model in the Java form in a Kotlin project.

package com.amazonaws.models.nosql; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBAttribute; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBHashKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBIndexHashKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBIndexRangeKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBRangeKey; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBTable; import java.util.List; import java.util.Map; import java.util.Set; @DynamoDBTable(tableName = "Books") class BooksDO { @DynamoDBHashKey(attributeName = "ISBN") @DynamoDBAttribute(attributeName = "ISBN") var isbn: String? = null @DynamoDBRangeKey (attributeName = "Category") @DynamoDBAttribute(attributeName = "Category") var category: String? = null @DynamoDBIndexHashKey(attributeName = "Author", globalSecondaryIndexName = "Author") var author: String? = null @DynamoDBIndexRangeKey(attributeName = "Title", globalSecondaryIndexName = "Title") var title: String? = null }
iOS - Swift

In the Xcode project explorer, right-click the folder containing your app delegate, and choose New File > Swift File > Next. Type the name you will use to refer to your data model as the filenam. In this example the name would be Books. Add code in the following form.

import Foundation import UIKit import AWSDynamoDB class Books: AWSDynamoDBObjectModel, AWSDynamoDBModeling { @objc var _isbn: String? @objc var _category: String? @objc var _author: String? @objc var _title: String? class func dynamoDBTableName() -> String { return "Books" } class func hashKeyAttribute() -> String { return "_isbn" } class func rangeKeyAttribute() -> String { return "_category" } override class func jsonKeyPathsByPropertyKey() -> [AnyHashable: Any] { return [ "_isbn" : "ISBN", "_category" : "Category", "_author" : "Author", "_title" : "Title", ] } }

Perform CRUD Operations

The fragments below consume the BooksDO data model class created in a previous step.

Create (Save) an Item

Use the following code to create an item in your NoSQL Database table.

Android - JavaAndroid - KotliniOS - Swift
Android - Java
public void createBooks() { final com.amazonaws.models.nosql.BooksDO booksItem = new com.amazonaws.models.nosql.BooksDO(); booksItem.setIsbn("ISBN1"); booksItem.setAuthor("Frederick Douglas"); booksItem.setTitle("Escape from Slavery"); booksItem.setCategory("History"); new Thread(new Runnable() { @Override public void run() { dynamoDBMapper.save(booksItem); // Item saved } }).start(); }
Android - Kotlin
fun createBooks() { val booksItem = BooksDO().apply { isbn = "ISBN1" author = "Frederick Douglas" title = "Escape from Slavery" category = "History" } thread(start = true) { ddbMapper.save(booksItem) } }
iOS - Swift
func createBooks() { let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default() let booksItem: Books = Books() booksItem._isbn = "1234" booksItem._category = "History" booksItem._author = "Harriet Tubman" booksItem._title = "My Life" //Save a new item dynamoDbObjectMapper.save(booksItem, completionHandler: { (error: Error?) -> Void in if let error = error { print("Amazon DynamoDB Save Error: \(error)") return } print("An item was saved.") }) }

Read (Load) an Item

Use the following code to read an item in your NoSQL Database table.

Android - JavaAndroid - KotliniOS - Swift
Android - Java
public void readBooks() { new Thread(new Runnable() { @Override public void run() { com.amazonaws.models.nosql.BooksDO booksItem = dynamoDBMapper.load( com.amazonaws.models.nosql.BooksDO.class, "ISBN1", // Partition key (hash key) "History"); // Sort key (range key) // Item read Log.d(LOG_TAG, String.format("Books Item: %s", booksItem.toString())); } }).start(); }
Android - Kotlin
fun readBooks() { thread(start = true) { val booksItem = ddbMapper.load(BooksDO::class.java, "ISBN1", // Partition Key (hash key) "History") // Sort key (range key) Log.d(LOG_TAG, "Books Item: $booksItem") } }
iOS - Swift
func readBooks() { let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default() // Create data object using data model you created let booksItem: Books = Books(); dynamoDbObjectMapper.load( Books.self, hashKey: "1234", rangeKey: "Harriet Tubman", completionHandler: { (objectModel: AWSDynamoDBObjectModel?, error: Error?) -> Void in if let error = error { print("Amazon DynamoDB Read Error: \(error)") return } print("An item was read.") }) }

Update an Item

Use the following code to update an item in your NoSQL Database table.

Android - JavaAndroid - KotliniOS - Swift
Android - Java
public void updateBooks() { final com.amazonaws.models.nosql.BooksDO booksItem = new com.amazonaws.models.nosql.BooksDO(); booksItem.setIsbn("ISBN1"); booksItem.setCategory("History"); booksItem.setAuthor("Frederick M. Douglas"); // booksItem.setTitle("Escape from Slavery"); new Thread(new Runnable() { @Override public void run() { // Using .save(bookItem) with no Title value makes that attribute value equal null // The .Savebehavior shown here leaves the existing value as is dynamoDBMapper.save(booksItem, new DynamoDBMapperConfig(DynamoDBMapperConfig.SaveBehavior.UPDATE_SKIP_NULL_ATTRIBUTES)); // Item updated } }).start(); }
Android - Kotlin
fun updateBooks() { val booksItem = BooksDO().apply { isbn = "ISBN1" category = "History" author = "Frederick M. Douglas" // Do not set title - it will be removed from the item in DynamoDB } thread(start = true) { ddbMapper.save(booksItem, DynamoDBMapperConfig(DynamoDBMappConfig.SaveBehavior.UPDATE_SKIP_NULL_ATTERIBUTES)) } }
iOS - Swift
func updateBooks() { let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default() let booksItem: Books = Books() booksItem._isbn = "1234" booksItem._category = "History" booksItem._author = "Harriet Tubman" booksItem._title = "The Underground Railroad" dynamoDbObjectMapper.save(booksItem, completionHandler: {(error: Error?) -> Void in if let error = error { print(" Amazon DynamoDB Save Error: \(error)") return } print("An item was updated.") }) }

Delete an Item

Use the following code to delete an item in your NoSQL Database table.

Android - JavaAndroid - KotliniOS - Swift
Android - Java
public void deleteBooks() { new Thread(new Runnable() { @Override public void run() { com.amazonaws.models.nosql.BooksDO booksItem = new com.amazonaws.models.nosql.BooksDO(); booksItem.setIsbn("ISBN1"); //partition key booksItem.setCategory("History"); //range key dynamoDBMapper.delete(booksItem); // Item deleted } }).start(); }
Android - Kotlin
fun deleteBook() { thread(start = true) { val booksItem = BooksDO().apply { isbn = "ISBN1" // Partition key category = "History" // Range key } ddbMapper.delete(booksItem) } }
iOS - Swift
func deleteBooks() { let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default() let itemToDelete = Books() itemToDelete?._isbn = "1234" itemToDelete?._category = "History" dynamoDbObjectMapper.remove(itemToDelete!, completionHandler: {(error: Error?) -> Void in if let error = error { print(" Amazon DynamoDB Save Error: \(error)") return } print("An item was deleted.") }) }

Perform a Query

A query operation enables you to find items in a table. You must define a query using both the hash key (partition key) and range key (sort key) attributes of a table. You can filter the results by specifying the attributes you are looking for. For more information about DynamoDBQueryExpression, see the AWS Mobile SDK for Android API reference.

The following example code shows querying for books with partition key (hash key) ISBN and sort key (range key) Category beginning with History.

Android - JavaAndroid - KotliniOS - Swift
Android - Java
public void queryBook() { new Thread(new Runnable() { @Override public int hashCode() { return super.hashCode(); } @Override public void run() { com.amazonaws.models.nosql.BooksDO book = new com.amazonaws.models.nosql.BooksDO(); book.setIsbn("ISBN1"); //partition key book.setCategory("History"); //range key Condition rangeKeyCondition = new Condition() .withComparisonOperator(ComparisonOperator.BEGINS_WITH) .withAttributeValueList(new AttributeValue().withS("History")); DynamoDBQueryExpression queryExpression = new DynamoDBQueryExpression() .withHashKeyValues(book) .withRangeKeyCondition("Category", rangeKeyCondition) .withConsistentRead(false); PaginatedList<BooksDO> result = dynamoDBMapper.query(com.amazonaws.models.nosql.BooksDO.class, queryExpression); Gson gson = new Gson(); StringBuilder stringBuilder = new StringBuilder(); // Loop through query results for (int i = 0; i < result.size(); i++) { String jsonFormOfItem = gson.toJson(result.get(i)); stringBuilder.append(jsonFormOfItem + "\n\n"); } // Add your code here to deal with the data result Log.d("Query results: ", stringBuilder.toString()); if (result.isEmpty()) { // There were no items matching your query. } } }).start(); }
Android - Kotlin
fun queryBooks() { thread(start = true) { val book = BooksDO().apply { isbn = "ISBN1" // Partition key category = "History" // Range key } val rangeKeyCondition = Condition() .withComparisonOperator(ComparisionOperator.BEGINS_WITH) .withAttrbiuteValueList(AttributeValue().withS("History")) val queryExpression = DynamoDBQUeryExpression() .withHashKeyValues(book) .withRangeKeyCondition("Category", rangeKeyCondition) .withConsistentRead(false) val result = ddbMapper.query(BooksDO::class.java, queryExpression) as PaginatedList<BooksDO> if (result.isEmpty()) { // There were no items matching your query } else { // loop through the result list and process the response } } }
iOS - Swift
func queryBooks() { // 1) Configure the query let queryExpression = AWSDynamoDBQueryExpression() queryExpression.keyConditionExpression = "#isbn = :ISBN AND #category = :Category" queryExpression.expressionAttributeNames = [ "#isbn": "ISBN", "#category": "Category" ] queryExpression.expressionAttributeValues = [ ":ISBN" : "1234", ":Category" : "History" ] // 2) Make the query let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default() dynamoDbObjectMapper.query(Books.self, expression: queryExpression) { (output: AWSDynamoDBPaginatedOutput?, error: Error?) in if error != nil { print("The request failed. Error: \(String(describing: error))") } if output != nil { for books in output!.items { let booksItem = books as? Books print("\(booksItem!._title!)") } } } }

Next Steps