DynamoDB Filter Expressions
After DynamoDB retrieves items using a Query or Scan, you can apply a Filter Expression to keep only the items that match specific conditions. This is a post-retrieval filter — DynamoDB fetches the data first and then applies the filter before returning results to you.
A Key Misunderstanding to Avoid
Many developers assume a Filter Expression tells DynamoDB which items to read. It does not. DynamoDB reads items based on the primary key (for Query) or the full table (for Scan). The Filter Expression only decides which of those read items to return to the caller.
This means Filter Expressions do not reduce read costs. You are charged for every item DynamoDB reads, whether it passes the filter or not.
Analogy
Imagine a restaurant bringing you the entire buffet on your table, and you pick only the dishes you like. You still pay for the full buffet. The Filter Expression is your picking — not the serving.
How Filter Expressions Work
Query: UserID = "U001" DynamoDB fetches all items for U001: ┌──────────┬────────────┬──────────┬────────┐ │ UserID │ OrderDate │ Product │ Amount │ ├──────────┼────────────┼──────────┼────────┤ │ U001 │ 2024-01-05 │ Laptop │ 85000 │ ← passes filter │ U001 │ 2024-03-12 │ Mouse │ 1200 │ ← filtered out │ U001 │ 2024-06-20 │ Monitor │ 22000 │ ← passes filter └──────────┴────────────┴──────────┴────────┘ FilterExpression: Amount > 10000 Result returned to you: ┌──────────┬────────────┬──────────┬────────┐ │ U001 │ 2024-01-05 │ Laptop │ 85000 │ │ U001 │ 2024-06-20 │ Monitor │ 22000 │ └──────────┴────────────┴──────────┴────────┘ DynamoDB read 3 items. You received 2. You were charged for 3.
Filter Expression Syntax
Filter Expressions use attribute names, comparison operators, and placeholder values. Placeholder names start with # and placeholder values start with :.
Basic Comparison Example
FilterExpression: "#amt > :minAmount"
ExpressionAttributeNames: { "#amt": "Amount" }
ExpressionAttributeValues: { ":minAmount": { "N": "10000" } }
The # prefix is needed because Amount could conflict with a DynamoDB reserved word. Using #amt avoids any naming conflicts.
Supported Comparison Operators
| Operator | Meaning | Example |
|---|---|---|
| = | Equal to | Status = "Delivered" |
| <> | Not equal to | Status <> "Cancelled" |
| < | Less than | Age < 18 |
| <= | Less than or equal | Price <= 500 |
| > | Greater than | Score > 90 |
| >= | Greater than or equal | Experience >= 5 |
| BETWEEN | Within a range | Price BETWEEN 100 AND 500 |
| begins_with | Starts with a string | ProductName begins_with "Smart" |
| contains | String or set contains value | Tags contains "Electronics" |
| attribute_exists | Attribute is present in the item | attribute_exists(Email) |
| attribute_not_exists | Attribute is absent from the item | attribute_not_exists(DeletedAt) |
| attribute_type | Attribute is a specific data type | attribute_type(Price, N) |
| size | Length of a string or set | size(Description) < 500 |
Combining Conditions
Use AND, OR, and NOT to combine multiple conditions.
Example: Active Premium Users
FilterExpression: "#status = :active AND #plan = :premium"
ExpressionAttributeNames:
"#status": "AccountStatus"
"#plan": "Plan"
ExpressionAttributeValues:
":active": { "S": "Active" }
":premium": { "S": "Premium" }
Example: Items That Are Not Cancelled
FilterExpression: "NOT #status = :cancelled"
ExpressionAttributeNames: { "#status": "Status" }
ExpressionAttributeValues: { ":cancelled": { "S": "Cancelled" } }
Filter Expressions vs Key Conditions
| Feature | Key Condition Expression | Filter Expression |
|---|---|---|
| Applied | Before reading from storage | After reading from storage |
| Reduces read cost | Yes | No |
| Can use | Partition key and sort key only | Any attribute |
| Available in | Query only | Query and Scan |
Practical Example: Support Ticket System
TABLE: Tickets (PK: CustomerID, SK: TicketDate) GOAL: Get open high-priority tickets for Customer C100 this year Step 1 — Key Condition (efficient — reduces storage reads): CustomerID = "C100" AND TicketDate begins_with "2024" Step 2 — Filter Expression (applied after storage read): Status = "Open" AND Priority = "High" DynamoDB reads all 2024 tickets for C100 (maybe 40 tickets) Returns only Open + High Priority ones (maybe 5 tickets) Charge: 40 tickets read
When Filter Expressions Hurt Performance
Filter Expressions cause a problem with pagination. DynamoDB applies the 1 MB page limit before filtering. If DynamoDB reads 1 MB of data and the filter removes 90% of it, your page returns very few items even though you requested a full page. You might need many pagination rounds to collect enough results.
The fix: design your primary keys and indexes to pre-filter data at the key condition level, so the Filter Expression is never doing heavy lifting on large datasets.
Summary
- Filter Expressions narrow down results after DynamoDB reads them from storage.
- They do not reduce the number of items DynamoDB reads or the cost you pay.
- Use key conditions (partition key and sort key) for the heavy filtering to minimize cost.
- Apply Filter Expressions only for light additional filtering on small result sets.
- Design your table keys and indexes to do the real work — not Filter Expressions.
