Amazon DynamoDB is a fully managed NoSQL database service designed for high availability and low latency at any scale. It uses a key-value and document data model and is widely used for serverless and scalable applications. Let us delve into understanding how to query DynamoDB using a hashkey and range key.
1. Introduction to DynamoDB
Amazon DynamoDB is a fully managed NoSQL database service provided by AWS that offers high performance at scale with seamless horizontal scaling, low-latency reads/writes, and automatic replication across multiple Availability Zones.
DynamoDB organizes data into tables, where each table requires a uniquely defined Primary Key. The primary key plays a critical role in uniquely identifying each item in the table and directly influences data access patterns.
There are two types of primary keys supported by DynamoDB:
- Simple Primary Key: Consists of only a Partition Key (also called
HASHkey). Each item in the table is uniquely identified by this partition key. - Composite Primary Key: Consists of a Partition Key and a Sort Key (also called
HASH + RANGE). This enables multiple items with the same partition key but different sort keys to exist, allowing finer granularity and logical grouping.
You can learn more about how primary keys work in DynamoDB.
Querying in DynamoDB becomes especially powerful with the use of a composite primary key. When you query using a Partition Key and Sort Key combination, you can:
- Efficiently retrieve all items with the same partition key.
- Apply key condition expressions to filter based on the Sort Key (e.g., greater than, begins_with, between).
- Perform range queries using the Sort Key to fetch items in a specific logical order or range.
This makes DynamoDB an excellent choice for use cases such as time-series data, user activity tracking, order history, and more, where data naturally fits into grouped and ordered records.
1.1 DynamoDB Setup on Docker and Mock Data Setup
1.1.1 Start Local DynamoDB using Docker
To begin experimenting with DynamoDB locally, you can use the official DynamoDB Local Docker image provided by AWS. This eliminates the need to interact with the actual AWS cloud during development and testing, making it faster and cost-effective.
Run the following Docker command to start a local DynamoDB instance on port 8000:
docker run -p 8000:8000 amazon/dynamodb-local
1.1.2 Create Table with Composite Key and Insert Sample Data
Once the local DynamoDB is up and running, the next step is to create a table with a composite primary key, consisting of a CustomerId as the Partition Key and OrderDate as the Sort Key.
-- Following AWS CLI command will create a table.
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions AttributeName=CustomerId,AttributeType=S AttributeName=OrderDate,AttributeType=S \
--key-schema AttributeName=CustomerId,KeyType=HASH AttributeName=OrderDate,KeyType=RANGE \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--endpoint-url http://localhost:8000
-- After creating the table, you can insert some sample data.
aws dynamodb batch-write-item --request-items '{
"Orders": [
{
"PutRequest": {
"Item": {
"CustomerId": {"S": "CUST001"},
"OrderDate": {"S": "2024-06-01"},
"Amount": {"N": "100"}
}
}
},
{
"PutRequest": {
"Item": {
"CustomerId": {"S": "CUST001"},
"OrderDate": {"S": "2024-06-05"},
"Amount": {"N": "200"}
}
}
},
{
"PutRequest": {
"Item": {
"CustomerId": {"S": "CUST001"},
"OrderDate": {"S": "2024-06-10"},
"Amount": {"N": "300"}
}
}
}
]
}' --endpoint-url http://localhost:8000
The snippet demonstrates how to create and populate a DynamoDB table named Orders using the AWS CLI while working with a local DynamoDB instance.
- The
create-tablecommand sets up the table with a composite primary key, whereCustomerIdserves as the partition key (HASH) andOrderDateas the sort key (RANGE). Both attributes are defined as strings. The table is configured with provisioned throughput settings of 5 read and 5 write capacity units. - After the table is successfully created, the
batch-write-itemcommand is used to insert multiple records into the table in a single operation. These records represent orders placed by customerCUST001on three different dates with corresponding amounts of100,200, and300. - The
--endpoint-urloption points tohttp://localhost:8000, indicating that these operations are performed on a locally running DynamoDB instance, typically started using Docker.
2. Java Code Examples for Querying
Now that you have a DynamoDB table with sample data locally running, itβs time to interact with it using Java. This section covers how to set up the required SDK dependencies and implement a basic Java program to query the Orders table using a partition key and optionally filter by sort key.
2.1 Add Dependency
To communicate with DynamoDB from a Java application, youβll need to include the AWS SDK for DynamoDB. If you are using Maven as your build tool, add the following dependency to your pom.xml:
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>dynamodb</artifactId> <version>latest__jar__version</version> </dependency>
2.2 Code Example
The following Java code demonstrates how to initialize a DynamoDB client, build a query request using a partition key (e.g., CustomerId), and retrieve the matching items. It assumes you are working with the locally hosted DynamoDB instance.
//DynamoDBQueryExample.java
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DynamoDBQueryExample {
public static void main(String[] args) {
// Create DynamoDB client
DynamoDbClient dynamoDb = DynamoDbClient.builder()
.endpointOverride(URI.create("http://localhost:8000")) // Local Docker
.region(Region.US_EAST_1)
.credentialsProvider(AnonymousCredentialsProvider.create()) // For local
.build();
System.out.println("Querying orders for CUST001 after 2024-06-01...");
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":custId", AttributeValue.fromS("CUST001"));
expressionValues.put(":startDate", AttributeValue.fromS("2024-06-01"));
QueryRequest request = QueryRequest.builder()
.tableName("Orders")
.keyConditionExpression("CustomerId = :custId AND OrderDate >= :startDate")
.expressionAttributeValues(expressionValues)
.limit(2) // Enable pagination demo
.build();
QueryResponse response = dynamoDb.query(request);
printItems(response.items());
// Handle pagination
while (response.hasLastEvaluatedKey()) {
request = request.toBuilder()
.exclusiveStartKey(response.lastEvaluatedKey())
.build();
response = dynamoDb.query(request);
printItems(response.items());
}
dynamoDb.close();
}
private static void printItems(List<Map<String, AttributeValue>> items) {
for (Map<String, AttributeValue> item : items) {
System.out.println("CustomerId: " + item.get("CustomerId").s());
System.out.println("OrderDate : " + item.get("OrderDate").s());
System.out.println("Amount : " + item.get("Amount").n());
System.out.println("-----");
}
}
}
2.2.1 Code Explanation
The DynamoDBQueryExample class demonstrates how to query a local DynamoDB table named Orders using the AWS SDK for Java. It first creates a DynamoDbClient configured to point to a locally running DynamoDB instance (using endpointOverride with http://localhost:8000) and anonymous credentials for local access. The application prints a message indicating it is querying orders for the customer CUST001 where the OrderDate is on or after 2024-06-01. It constructs a QueryRequest using a keyConditionExpression with both the partition key (CustomerId) and a range condition on the sort key (OrderDate >= :startDate). The query is limited to two results per page using the limit(2) setting to demonstrate pagination. After the initial query, the code checks for more results using hasLastEvaluatedKey() and continues fetching the remaining pages by updating the request with exclusiveStartKey. For each page, it calls the printItems() method, which iterates over the result items and prints CustomerId, OrderDate, and Amount fields for each order. Finally, the DynamoDB client is closed to release resources.
2.2.2 Code Output
Upon execution, the code produces the following output:
Querying orders for CUST001 after 2024-06-01... CustomerId: CUST001 OrderDate : 2024-06-01 Amount : 100 ----- CustomerId: CUST001 OrderDate : 2024-06-05 Amount : 200 ----- CustomerId: CUST001 OrderDate : 2024-06-10 Amount : 300 -----
3. Conclusion
Querying in DynamoDB using Partition and Sort keys allows developers to structure their data access patterns efficiently. Whether you are retrieving all orders for a customer or filtering by date ranges, DynamoDB provides powerful query capabilities. By leveraging Docker for local development and Java SDK for integration, teams can build robust serverless applications with predictable and scalable query performance.
Thank you!
We will contact you soon.
Yatin BatraJune 23rd, 2025Last Updated: June 23rd, 2025

This site uses Akismet to reduce spam. Learn how your comment data is processed.