DynamoDB is Amazon’s managed NoSQL database service. This blog will be focusing on data retrieval and how it is critical to think about what your data will look like, to make an informed decision about your database design.

When working with DynamoDB there is really two ways of retrieving information — one being scanning and filtering and the other being querying the database! So what is the difference and what should I use?

Before we get started, something we will be talking about a lot is partition keys, so let’s start with a short definition of what this is:

Partition Key — Is a primary key that DynamoDB uses to partition the data and determine storage.

First things first, what is scanning?

Example:

const item = {
employeeID: { S: "4beb73f0-2fc0-41b2-a8e9" },
startDate: { S: "2020-05-09T17:53:00+00:00" }
name: { S: "example-name" },
title: { S: "example-title" },
}

We could scan the database using the following as our scan params:

const params = {
TableName: "employees",
ProjectionExpression: "employeeID, name",
FilterExpression: "title = :title",
ExpressionAttributeValues: {
":title": {S: "example-title"}
}
};

The above code snippet would scan each item and would then filter for items that have a title the same as the one specified! The filter expression here could filter for any column/attributes in this database (e.g. employeeID, startDate, name, title).

But what is querying and why is it different?

Example:

item = {
employeeID: { S: "4beb73f0-2fc0-41b2-a8e9" },
startDate: { S: "2020-05-09T17:53:00+00:00" },
name: { S: "example-name" },
title: { S: "example-title" },
}

Since we want to query the table this time, we can make use of employeeID as the partition key and we would be able to write query params like this, where our KeyConditionExpression is looking for a particular ID:

queryParams = {
tableName = "employees",
KeyConditionExpression: "employeeID = :id",
ExpressionAttributeValues: {
":id": "4beb73f0-2fc0-41b2-a8e9",
},
}

With using the partition key the query would be more efficient as it doesn’t need to read each item in the database, because DynamoDB stores and retrieves each item based on this partition key value!

But what if we want to Query for something that is not the partition key?

At the minute with our current set up, we would not be able to write a query for this because as I mentioned before — queries need to use the partition key in the equality condition! However, there is still a way we could query for this without having to do a scan.

Secondary Indexes

You can create multiple secondary indexes on a db, which would give your applications access to a lot more query patterns.

We can create a secondary index on DyanmoDB by specifying the partition key for it and naming the index:

Now with our secondary index set up, we can go ahead and query using it:

queryParams  = {
"TableName": "employees",
"IndexName": "name-index",
"ProjectionExpression": "employeeID, startDate, name, title",
"KeyConditionExpression": "name= :name",
"ExpressionAttributeValues": {
":name": {S: "example-name"}
}
};

Notice that we are using the new secondary index within our query. We can now find the employee details by using the employees name!

Setting up secondary indexes do have associated costs, but when working with large amounts of data, it can really increase the performance and efficiency of data retrieval. It can get items based on storage location without having to read every item in the whole database.

To improve efficiency further, you could also look into adding composites keys or indexes which can be made up of a partition key and a sort key.

Scan or Query?

And honestly, it all depends on the size and amount of data you are working with!

If you are working with a small amount of data, you could totally go for scanning and filtering the database and not have to worry about adding all these extra keys. If the data is already small, the scan time won’t take long anyway, so adding in things like secondary keys to partition into even smaller sets, isn’t likely to increase your performance by a significant amount and therefore might not be worth the additional overhead of implementing these.

However, if you are working with large amounts of data, that is likely to keep growing — it is really worth spending time and making sure you choose the right secondary indexes.

When creating a database with indexes, it is really beneficial to spend time considering what queries are you likely to be doing. Understanding what data you will need to retrieve will help you choose your partition keys. Taking the initial time to think this through will make sure your database is set up the right way for you to retrieve data from it in the quickest, most efficient manner! Failure to think about this up front may limit you data access points down the line.

Software Engineer