AWS
DynamoDB
KeyConditionExpression
Querying Database
Cloud Computing

How to query AWS DynamoDb using KeyConditionExpression?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In DynamoDB, KeyConditionExpression is how you tell the Query operation which partition key value to read and, optionally, how to narrow the sort-key range. It is not a general filter for arbitrary attributes. The partition key must be matched by equality, and only the sort key can use range-style operators in the key condition.

What KeyConditionExpression Can Do

According to the DynamoDB docs, a Query must specify the partition key as an equality condition. You may also add a sort-key condition using operators such as:

  • '='
  • '<'
  • '<='
  • '>'
  • '>='
  • 'BETWEEN'
  • 'begins_with'

So a valid key condition looks like:

CustomerId = :customerId AND begins_with(OrderDate, :prefix)

That works only if CustomerId is the partition key and OrderDate is the sort key for the table or index being queried.

Basic Boto3 Example

python
1import boto3
2from boto3.dynamodb.conditions import Key
3
4dynamodb = boto3.resource("dynamodb", region_name="us-east-1")
5table = dynamodb.Table("Orders")
6
7response = table.query(
8    KeyConditionExpression=Key("CustomerId").eq("cust-123")
9)
10
11for item in response["Items"]:
12    print(item)

This returns all items whose partition key is cust-123, sorted by the table's sort key if one exists.

Query With a Sort-Key Range

python
1response = table.query(
2    KeyConditionExpression=
3        Key("CustomerId").eq("cust-123") &
4        Key("OrderDate").between("2025-01-01", "2025-12-31")
5)

This is a classic pattern when the partition key groups related items and the sort key represents time or sequence.

FilterExpression Is Not the Same Thing

Many DynamoDB beginners try to put non-key conditions into KeyConditionExpression. That is not allowed.

Use this rule:

  • 'KeyConditionExpression narrows which partition and sort-key range DynamoDB reads'
  • 'FilterExpression removes extra items after the query has already read them'

That distinction matters for performance. Filtered-out items still consume read capacity because DynamoDB had to read them before filtering.

If your access pattern depends on a different partition key, the right answer is often a secondary index rather than a more complicated filter expression.

Placeholder Names and Reserved Words

If an attribute name collides with a reserved word, use expression attribute names:

python
1response = table.query(
2    KeyConditionExpression="#pk = :pk",
3    ExpressionAttributeNames={"#pk": "CustomerId"},
4    ExpressionAttributeValues={":pk": "cust-123"},
5)

The higher-level Key(...) helper is often cleaner, but the placeholder form is important when you are constructing expressions dynamically.

Pagination Matters

DynamoDB query responses are limited. The docs note that a single Query call returns up to 1 MB before filtering or projection is applied. If LastEvaluatedKey is present, you must paginate:

python
1items = []
2kwargs = {
3    "KeyConditionExpression": Key("CustomerId").eq("cust-123")
4}
5
6while True:
7    response = table.query(**kwargs)
8    items.extend(response["Items"])
9
10    last_key = response.get("LastEvaluatedKey")
11    if not last_key:
12        break
13
14    kwargs["ExclusiveStartKey"] = last_key

Ignoring pagination is a common reason queries appear to "miss" data.

You can also control sort-key order in query results with ScanIndexForward. By default it is ascending. Set it to False when you want newest-first or highest-sort-key-first results.

Common Pitfalls

The biggest mistake is trying to query DynamoDB without the partition key. Query does not work that way; use Scan or redesign the key schema or index.

Another mistake is putting non-key attributes into KeyConditionExpression. Those belong in FilterExpression, if anywhere.

A third issue is forgetting that results are sorted by the sort key and returned ascending by default unless you set ScanIndexForward=False.

Summary

  • 'KeyConditionExpression must include partition-key equality.'
  • It can also include sort-key conditions such as range checks or begins_with.
  • Non-key filtering belongs in FilterExpression, not the key condition.
  • Use pagination when LastEvaluatedKey is returned.
  • Design your table or index so the access pattern matches a real key-based query.

Course illustration
Course illustration

All Rights Reserved.