Query an item collection

Amazon DynamoDB · Essentials · 12 min

Query is the efficient way to read many items and the operation most access patterns are built on.

Query reads items from one item collection: you must give an equality condition on the partition key, and you may add one condition on the sort key: =, <, <=, >, >=, between, or begins_with.

With the boto3 resource you build these with boto3.dynamodb.conditions.Key:

Key("customer_id").eq("c1") & Key("order_id").begins_with("2025-03")

Results come back sorted by sort key, ascending by default; ScanIndexForward=False returns them descending, which together with Limit=1 is the idiom for "latest item" (most recent order, last reading of a sensor).

Because a query reads one contiguous range on one partition, its cost depends only on the size of the items it reads, not on the size of the table. That is why designs that turn access patterns into queries scale so well.

A query returns at most 1 MB of data per call. If there is more, the response contains LastEvaluatedKey and you must call again with ExclusiveStartKey (see pagination).

A FilterExpression can drop items after they are read, but you still pay for reading them; filters are a convenience, not a substitute for good keys.

Example

import boto3
from boto3.dynamodb.conditions import Key

table = boto3.resource("dynamodb").Table("Orders")
for oid in ["2025-01-09#A11", "2025-03-01#A17", "2025-03-14#A20"]:
    table.put_item(Item={"customer_id": "c1", "order_id": oid})

march = table.query(
    KeyConditionExpression=Key("customer_id").eq("c1")
                           & Key("order_id").begins_with("2025-03"))
print([i["order_id"] for i in march["Items"]])
# ['2025-03-01#A17', '2025-03-14#A20']

latest = table.query(KeyConditionExpression=Key("customer_id").eq("c1"),
                     ScanIndexForward=False, Limit=1)
print(latest["Items"][0]["order_id"])   # 2025-03-14#A20

Remember

  • Query needs partition key equality and allows one sort key condition
  • Results are ordered by sort key; ScanIndexForward=False reverses
  • Cost depends on items read, not table size
  • FilterExpression runs after the read and does not reduce cost

Watch out for

  • Expecting a FilterExpression to make a query cheaper; you pay for everything read before filtering.

Check yourself

  1. How do you get the most recent order for c1 when order_id starts with an ISO date?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html