GraphQL Query Capabilities: Filters, Windows, Aggregates, Joins
A Bitquery query is a GraphQL selection on a cube with four kinds of building blocks. Filters in where narrow rows by address, token, amount, date or a relative window such as the last 30 minutes. orderBy and limit shape the result, including sorting by an aggregate you define. Metrics such as count, sum, uniq, quantile and calculate turn rows into numbers, with if conditions so one query returns buys and sells side by side. Joins, array intersection and JSON argument filters reach across cubes and into decoded contract data. All of it runs as a query or a subscription, and the same syntax works on every chain.
Pick the capability
| You want to | Read |
|---|---|
| Filter by address, token, amount, block or transaction fields | Query filters |
| Filter by a date range | Date and time filters |
| Filter by "the last N minutes" with no date to update | Relative time filters |
| Sort by a field or by an aggregate | Sorting results |
| Know the row and time limits a query can hit | Query limits |
| Sum, count, distinct, quantile, min and max over rows | Aggregated metrics |
| Compute a new number from other fields or aggregates | Calculations and expressions and Expressions |
| Return the rows themselves, not aggregates | Fact records |
| Stream rows or aggregates over WebSocket | Subscription on facts and Subscription on aggregates |
| Combine two cubes in one call | Joins |
| Match rows whose array field overlaps a list | Array intersection |
| Filter on decoded contract arguments | Filtering JSON arguments |
| Use a combined dataset that stitches archive and realtime | Combined dataset |
| Know which fields are indexed for fast filters and sorts | Indexed fields reference |
| Make a slow query fast | Optimizing queries |
| Drop wash trades and bad prices | Filtering abnormal prices |
| Call the API from Postman | GraphQL in Postman |
| Understand the schema shape first | Query principles |
Several capabilities in one query
Relative time window, a success filter, two aggregated prices with aliases, a calculation over them and a sort by an aggregate: price change of WSOL against USDC per DEX over the last 30 minutes. Run it in the Bitquery IDE on a free account.
{
Solana {
DEXTradeByTokens(
where: {
Trade: {
Currency: { MintAddress: { is: "So11111111111111111111111111111111111111112" } }
Side: { Currency: { MintAddress: { is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" } } }
}
Block: { Time: { since_relative: { minutes_ago: 30 } } }
Transaction: { Result: { Success: true } }
}
orderBy: { descendingByField: "trades" }
limit: { count: 3 }
) {
Trade {
Dex {
ProtocolName
}
first: PriceInUSD(minimum: Block_Time)
last: PriceInUSD(maximum: Block_Time)
}
trades: count
change_pct: calculate(expression: "($Trade_last - $Trade_first) / $Trade_first * 100")
}
}
}
Aliases inside Trade are referenced in calculate as $Trade_<alias>. The same shape works on EVM(network: eth) with SmartContract instead of MintAddress.
Frequently Asked Questions
Can I filter by a rolling time window instead of fixed dates?
Yes. since_relative and till_relative (and after_relative inside metric conditions) take minutes_ago, hours_ago or days_ago, so the window rolls forward every time the query runs. Fixed dates use since and till on Block.Time or Block.Date.
Can a single query return buys and sells separately?
Yes. Any metric takes an if condition, so sum(of: Trade_Side_AmountInUSD, if: {Trade: {Side: {Type: {is: buy}}}}) and the same with sell sit side by side in one row, and calculate can combine them.
Do aggregates work in subscriptions?
Yes, on the chain-level cubes: a subscription on aggregated metrics recomputes them as new rows arrive. Some features of the Trading cubes do not survive the conversion; the subscriptions section lists them.
How do I join two cubes?
With the joins capability: a selection inside one cube can pull matching rows from another, such as the transfers behind a trade or the balances of the traders you just found. The joins page has the syntax and the limits.
Why is my query slow or rejected?
Usually an unindexed filter, no time bound or a very wide window. Filter on indexed fields, bound the time, keep limit modest and read the optimizing guide; the limits page says what the API refuses outright.
Related pages
Ready to run this in production?
Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.