Relationships
You reach for a JOIN because the UI shows users beside their orders, and
DynamoDB has no server-side join operator. The expensive mistake is fetching each
side with separate GetItem calls — N+1 reads that scale with every row on screen.
Relationships in DynamoDB live in key design. You place related items in the same
item collection so one Query returns the graph you need, or you maintain
adjacency rows that point across collections. Many-to-many needs an explicit
bridge pattern; high fan-out needs composite sort keys and sometimes reference
counts to keep collections bounded.
What you can do after
- Model one-to-many by co-locating children under a parent partition key.
- Implement many-to-many with adjacency or bridge items without duplicating full records on every edge.
- Split wide hierarchies with composite sort keys so
begins_withqueries stay precise. - Maintain reference counts atomically when delete rules depend on "no children left."
Reading order
- One-to-many — children under one partition key; the base pattern every other relationship extends.
- Many-to-many — bridge items and dual-write patterns when either side can list the other.
- Adjacency list — graph-shaped data as items and edges; tree walks without recursive SQL.
- Composite sort keys — encode hierarchy in the sort key so range queries stay selective.
- Reference counts — conditional updates that gate deletes when fan-out must stay consistent.
A user profile at PK = USER#88 with orders at SK = ORDER#2026-08-01#K4 lets
you paint a profile screen from one Query. A many-to-many tag graph needs
bridge rows — skipping that step leaves you Scanning for edges.
Adjacency lists model trees and shallow graphs with PARENT# / CHILD# sort-key
prefixes so one begins_with query returns direct children. Composite sort keys
encode paths like LOCATION#US#CA#SF so range queries stay within a subtree.
Reference counts on a parent item gate deletes: referenceCount = :zero in a
condition expression prevents removing a category that still has products attached.
Each pattern trades write complexity for read efficiency — pick the one that matches
how often you list vs how often you reshape the graph.
Hands-on in DynoTable
Download DynoTable and open a table with parent/child keys. Run a
Query on the parent partition and watch the grid return the whole collection in
sort order. Right-click a composite key cell and filter to a prefix to see how
entity facets group in practice.
When you want the relational view anyway, the SQL Workbench
runs JOIN client-side over the rows you already fetched. That join is bounded by
what DynamoDB returned — it does not add a server-side join operator. Use it to
validate a key design, not to paper over a missing access pattern.
For ad-hoc parent/child layouts, the single-table design planner proposes PK/SK placement from your stated reads.