How to Store and Query Nested Data in DynamoDB
In DynamoDB, you can store nested data using
Map and List data types inside an item attribute. To query nested data, use ExpressionAttributeNames with dot notation in your KeyConditionExpression or FilterExpression to access nested attributes.Syntax
DynamoDB supports nested data using Map and List types inside an item attribute. You define nested attributes as JSON-like structures.
To access nested attributes in queries, use dot notation with placeholders in ExpressionAttributeNames. For example, to access address.city, use #addr.#city with {"#addr": "address", "#city": "city"}.
json
PutItem {
TableName: "Users",
Item: {
"UserId": { S: "123" },
"Name": { S: "Alice" },
"Address": { M: {
"City": { S: "Seattle" },
"Zip": { S: "98101" }
}}
}
}
Query {
TableName: "Users",
KeyConditionExpression: "UserId = :uid",
FilterExpression: "#addr.#city = :city",
ExpressionAttributeNames: { "#addr": "Address", "#city": "City" },
ExpressionAttributeValues: { ":uid": { S: "123" }, ":city": { S: "Seattle" } }
}Example
This example shows how to store a user with nested address data and query users living in a specific city.
javascript
const { DynamoDBClient, PutItemCommand, QueryCommand } = require("@aws-sdk/client-dynamodb"); const client = new DynamoDBClient({ region: "us-west-2" }); async function run() { // Store nested data await client.send(new PutItemCommand({ TableName: "Users", Item: { UserId: { S: "123" }, Name: { S: "Alice" }, Address: { M: { City: { S: "Seattle" }, Zip: { S: "98101" } }} } })); // Query nested attribute const data = await client.send(new QueryCommand({ TableName: "Users", KeyConditionExpression: "UserId = :uid", FilterExpression: "#addr.#city = :city", ExpressionAttributeNames: { "#addr": "Address", "#city": "City" }, ExpressionAttributeValues: { ":uid": { S: "123" }, ":city": { S: "Seattle" } } })); console.log(JSON.stringify(data.Items, null, 2)); } run();
Output
[
{
"UserId": { "S": "123" },
"Name": { "S": "Alice" },
"Address": {
"M": {
"City": { "S": "Seattle" },
"Zip": { "S": "98101" }
}
}
}
]
Common Pitfalls
- Trying to query nested attributes directly in
KeyConditionExpressionis not allowed; useFilterExpressioninstead. - For nested attributes, always use
ExpressionAttributeNamesto avoid reserved word conflicts. - Remember that
FilterExpressionfilters results after the query, so it can be less efficient.
sql
/* Wrong: Trying to query nested attribute in KeyConditionExpression */ // KeyConditionExpression: "Address.City = :city" <-- This will cause an error /* Right: Use FilterExpression with ExpressionAttributeNames */ // FilterExpression: "#addr.#city = :city", // ExpressionAttributeNames: { "#addr": "Address", "#city": "City" }
Quick Reference
| Concept | Description | Example |
|---|---|---|
| Map | Stores nested key-value pairs | {"Address": {"City": "Seattle", "Zip": "98101"}} |
| List | Stores ordered nested values | {"Tags": ["red", "blue", "green"]} |
| ExpressionAttributeNames | Placeholders for nested attribute names | {"#addr": "Address", "#city": "City"} |
| Dot Notation | Access nested attributes in expressions | "#addr.#city" |
| FilterExpression | Filter results by nested attribute | "#addr.#city = :city" |
Key Takeaways
Use DynamoDB Map and List types to store nested data inside item attributes.
Access nested attributes in queries using dot notation with ExpressionAttributeNames placeholders.
Use FilterExpression, not KeyConditionExpression, to filter by nested attributes.
Always use ExpressionAttributeNames to avoid reserved word conflicts with nested keys.
Filtering nested data happens after query, so design keys carefully for efficient access.