Bean & Bark: your first real query

View .md

Fourth day on the job. The whole store — 240,000 orders — lives in one DynamoDB table called BeanAndBark. There is no "revenue" button and no "find Dana" button. There is a query box, a founder who needs an answer, and eighteen minutes. This is where you learn the one distinction DynamoDB is built around: a Query that touches three items, versus a Scan that reads — and bills you for — all 240,000.

You'll learn
  • Tell a cheap Query from a full-table Scan — and read which one you got before you run it
  • See why what you read (and pay for) is not the same as what you asked for
  • Pull every order for one customer in a single read, using its partition key

Your first instinct is a trap

You know Dana's name, so you ask for it by name. It reads like plain English and it returns exactly the right orders — which is precisely why it's dangerous. CustomerName isn't a key, so DynamoDB has no door to walk through: it reads every item in the table and throws almost all of them away. That's a Scan.

sql
-- Your instinct: you know her name, so ask for it.SELECT OrderId, Placed, Status, TotalFROM "BeanAndBark"WHERE CustomerName = 'Dana Okafor'   -- a plain attribute → Scan

Before you run it — a guess. Of the 240,000 items, how many does DynamoDB read to hand back Dana's three orders? Flip between the two variants below and watch the "Executes as" strip: the first asks by name, the second asks by key. Same three orders come back. The bill does not.

Try it · find Dana's ordersSample
Executes asScan · BeanAndBark
Scan FilterExpression: CustomerName = 'Dana Okafor' · reads ~240,000 items at last describe
No key in the WHERE — so every one of the ~240,000 items is read and billed, then filtered down to three.
What you pay for is the read, not the three rows you wanted. Flip to "By key" to ask the same question for the price of one partition.
#OrderIdPlacedStatusTotal
1Order#88422026-06-19delivered$540
2Order#90132026-06-27shipped$360
3Order#91882026-07-01lost?$420
Fetched 3 items in 368ms · <0.01% efficient · 480 RCU · 22 partitions
Par1 RCU480× over par

Read the two footers. Same three orders, same answer for Nadia — but the Scan read ~240,000 items to find them (< 0.01% of what it touched was useful) and the Query read exactly 3 (100%). What DynamoDB reads is what you pay for; what it returns is only what you asked for. The whole craft is closing that gap — and a single partition key equality closes it completely.

Recap
  • A partition key equality is the one thing that turns a read into a cheap Query; a plain attribute like CustomerName forces a full Scan.
  • Read ≠ returned. You pay for every item DynamoDB reads, not the rows it hands back — the "Executes as" strip shows the gap before you run.
  • One partition key gives you a customer's whole collection of orders in a single, cheap read.
Before standup — check yourself2
You need one customer's orders from BeanAndBark (keys pk, sk). Which WHERE is a cheap Query?
The by-name Scan read ~240,000 items to return 3 rows. How many items do you pay for?
Try it yourself 2
1 Turn the Scan into a Query
This reads the whole table: SELECT * FROM "BeanAndBark" WHERE CustomerName = 'Dana Okafor'. Rewrite it to read only Dana's partition.
You looked her account up once — her partition key is CUSTOMER#c-014. Swap the name filter for a pk equality.
Show solution
Ask by key: pk = 'CUSTOMER#c-014' is the key condition (a Query), and begins_with(sk, 'ORDER#') keeps it to orders — one partition, nothing wasted.
sql
SELECT OrderId, Placed, Status, TotalFROM "BeanAndBark"WHERE pk = 'CUSTOMER#c-014' AND begins_with(sk, 'ORDER#')
2 Just the unshipped ones
Nadia only cares about orders that haven't shipped. Keep it a Query, but return only Dana's orders whose Status is still pending.
The pk equality stays (it's what keeps this a Query). Add Status as a filter within that partition — it's cheap here because you're only reading Dana's items.
Show solution
Keep the key condition and add a filter: Status = 'pending' runs against the handful of items in Dana's partition, not the whole table.
sql
SELECT OrderId, Placed, Status, TotalFROM "BeanAndBark"WHERE pk = 'CUSTOMER#c-014' AND begins_with(sk, 'ORDER#')  AND Status = 'pending'
Was this page helpful?