commerce
Customer Orders
A customer's order history, newest first, in one partition.
The canonical one-to-many collection. Orders share their customer's partition and sort by the date they were placed, so a customer's whole history is one Query and the recent end of it is the cheap end.
The model
Order
One order, sorted by the date it was placed.
- pk
- CUSTOMER#<customerId>
- sk
- ORDER#<placedOn>#<orderId>
Attributes: total (N), status (S), placedAt (N)
Customer
The customer record, at the head of its own collection.
- pk
- CUSTOMER#<customerId>
- sk
- CUSTOMER#<customerId>
Attributes: name (S), email (S)
Access patterns
- QueryRead a customer and their orders
The customer record and their whole order history, in one read.
- GetItemRead one order
A single order, by customer and order key.
Design notes
The date goes in the sort key, not just in an attributewhy
placedAt is on the item too, but the ordering comes from the sort key. A date attribute can only be filtered - every order read, then most of them discarded - while a date in the sort key is part of the key condition, so the rows you skip are never read. That is the same distinction the filter-trap lesson makes, applied to a collection that grows forever.
Newest first is a read-time choicetrade-off
The rows are stored ascending. Production passes ScanIndexForward=false to walk the collection backwards, so the most recent orders arrive first and a Limit of 20 costs twenty reads rather than the customer's entire history. That direction has a cost of its own: the customer record sorts first, so a descending read reaches it last, and an account page wanting the person plus their newest orders takes a separate GetItem for the header. The console here reads the collection as stored; direction is a property of the request, not of the table.
The customer sits in its own collectionwhy
CUSTOMER#c-ada appears as both partition and sort key, so the customer record sorts before every ORDER# in the same partition. One Query returns the person and their history together, which is what an account page needs, and the same read serves a page that only wants the person by stopping at the first row.
Windowing is the design, not the demotrade-off
A real order page asks for a date range - between two ORDER# prefixes - or the most recent N. The preview resolves only the partition half of a key condition, so the console reads the whole collection instead. The technique is unchanged and it is what the sort key is for; this page just cannot show you the narrower read.
Taught in the course
- One query, a whole collection - Items that share a partition key are read together in one Query.
- Read the latest first - A sorted timestamp makes 'the most recent' a direction, not a sort in your code.
- Model a one-to-many with one partition - A parent and its children share a partition key, so one Query fetches them together.
The customer record and their whole order history, in one read.
Run an operation to see the raw engine response.
The in-browser engine is a preview build. Transactions, vector search, streams, tags and TTL are among the operations it doesn't implement yet.