Build an Application Using a NoSQL Key-Value Data Store

GETTING STARTED GUIDE

Module 3: Querying and secondary indexes

Learn how to use secondary indexes to enable additional query patterns on your DynamoDB tables

Introduction

In this module, we'll walk through using secondary indexes. In the previous module, we explored how to retrieve additional information on a book when given the elements for our composite primary key (Author and Title). However, you may want to retrieve all books in a particular category, such as technology or biography. Unfortunately, Category is not a part of your table's primary key. However, you can create a secondary index to allow for this access pattern. The steps below show how we can implement this in our application.

 Time to Complete

15 minutes

 Prerequisites

  • An AWS account: if you don't already have one, follow the Setting Up Your Environment getting started guide for a quick overview.
  • An installed version of the AWS SDK via pip install boto3

Implementation

Step 1: Create secondary index

You can create the global secondary index at the time of table creation, but you can also specify it afterwards. The following code creates a global secondary index for the Books table. Similar to the process of creating a table and defining our primary key, we define which attribute will correlate with our secondary index. 

import boto3

# Boto3 is the AWS SDK library for Python.
# You can use the low-level client to make API calls to DynamoDB.
client = boto3.client('dynamodb', region_name='us-east-1')

try:
    resp = client.update_table(
        TableName=\"Books\",
        # Any attributes used in your new global secondary index must be declared in AttributeDefinitions.
        AttributeDefinitions=[
            {
                "AttributeName": "Category",
                "AttributeType": "S"
            },
        ],
        # This is where you add, update, or delete any global secondary indexes on your table.
        GlobalSecondaryIndexUpdates=[
            {
                "Create": {
                    # You need to name your index and specifically refer to it when using it for queries.
                    "IndexName": "CategoryIndex",
                    # Like the table itself, you need to specify the key schema for an index.
                    # For a global secondary index, you can use a simple or composite key schema.
                    "KeySchema": [
                        {
                            "AttributeName": "Category",
                            "KeyType": "HASH"
                        }
                    ],
                    # You can choose to copy only specific attributes from the original item into the index.
                    # You might want to copy only a few attributes to save space.
                    "Projection": {
                        "ProjectionType": "ALL"
                    },
                    # Global secondary indexes have read and write capacity separate from the underlying table.
                    "ProvisionedThroughput": {
                        "ReadCapacityUnits": 1,
                        "WriteCapacityUnits": 1,
                    }
                }
            }
        ],
    )
    print("Secondary index added!")
except Exception as e:
    print("Error updating table:")
    print(e)

Step 2: Query secondary index

Now that you have the CategoryIndex, you can use it to retrieve all books within a particular category.

import boto3
 
dynamodb = boto3.client('dynamodb', region_name='us-east-1') 
resp = dynamodb.execute_statement(Statement='SELECT * FROM Books.CategoryIndex WHERE Category = \'Technology\'')
print(resp['Items'])

Conclusion

In this module you created a secondary index to enable access to a data category that is not part of the table’s primary key. 

Up Next: Modifying items

Was this page helpful?