Cross-model queries
In SQL, every query that touches more than one table starts with a JOIN. AQL flips that around: relationships are declared once in your dataset, then any query just references the columns it needs.
Practice in the AQL Playground: Relationships.
The basic move
You're querying order_items. You want each item's product name (which lives on products). Just ask:
order_items
| select(order_items.id, products.name)
No join. AQL sees that order_items is related to products, generates the right join under the hood, and gives you the result.
Why this works
A dataset isn't just a list of tables. It's tables plus the relationships between them. Each model represents a business entity; each relationship records how those entities connect:
- An
order_itemsrow belongs to oneordersrow. - An
ordersrow belongs to onecustomersrow. - A
productsrow belongs to onemerchantsrow.
Because the relationships are known up front, AQL can resolve products.name from inside an order_items query the same way you'd say it in plain English.
Multi-hop is fine too
You can reach further as long as each hop is many-to-one:
order_items
| select(order_items.id, merchants.name)
Here AQL walks order_items → products → merchants. One item belongs to one product, which belongs to one merchant. So the chain is unambiguous.
The one rule: many-to-one only
You can reference the "one" side of a relationship freely. The "many" side is different. There isn't a single row to point at. From an orders row, order_items is a collection, not a value:
// This doesn't work: order_items.value is many rows
orders | select(orders.id, orders.discount * order_items.value)
To use the many side, you have to aggregate it first:
orders | select(orders.id, orders.discount * sum(order_items.value))
sum() collapses the collection back to a single number.
When relationships are ambiguous
If two models are connected by more than one path, AQL won't guess. Either deactivate the paths you don't want in the dataset, or override per-metric with with_relationships():
sum(order_items.revenue)
| with_relationships(order_items.product_id > products.id)
Next
→ Defining a metric: name an aggregation so you can reuse it instead of writing it out every time.