5.3 KiB
5.3 KiB
GraphQL Query Patterns for Subgraphs
This reference provides common GraphQL query patterns for blockchain subgraph exploration.
Pagination Patterns
Basic Pagination
query PaginatedQuery($first: Int!, $skip: Int!) {
entities(first: $first, skip: $skip, orderBy: timestamp, orderDirection: desc) {
id
timestamp
# ... other fields
}
}
Variables:
{
"first": 100,
"skip": 0
}
Cursor-based Pagination
query CursorPagination($first: Int!, $lastId: String!) {
entities(first: $first, where: { id_gt: $lastId }, orderBy: id) {
id
# ... other fields
}
}
Filtering Patterns
Time Range Queries
query TimeRangeQuery($startTime: Int!, $endTime: Int!) {
entities(
where: {
timestamp_gte: $startTime
timestamp_lte: $endTime
}
orderBy: timestamp
orderDirection: desc
) {
id
timestamp
# ... other fields
}
}
Address-based Queries
query UserActivity($userAddress: String!) {
# Query by exact address
transactions(where: { from: $userAddress }) {
id
to
value
timestamp
}
# Query by address (case-insensitive)
accounts(where: { id: $userAddress }) {
id
balance
# ... other fields
}
}
Complex Filters
query ComplexFilter($minAmount: String!, $tokenAddress: String!) {
swaps(
where: {
amountUSD_gte: $minAmount
pair_: {
token0: $tokenAddress
}
}
first: 100
orderBy: timestamp
orderDirection: desc
) {
id
amountUSD
timestamp
pair {
token0 { symbol }
token1 { symbol }
}
}
}
Aggregation Patterns
Daily Aggregates
query DailyStats($dayId: Int!) {
dayData(id: $dayId) {
id
date
dailyVolumeUSD
dailyTxns
totalLiquidityUSD
}
}
Sum and Count
query Aggregations {
protocol(id: "1") {
totalValueLockedUSD
txCount
pairCount
totalVolumeUSD
}
}
Relationship Navigation
Nested Queries
query NestedRelationships($pairId: String!) {
pair(id: $pairId) {
id
token0 {
id
symbol
name
decimals
}
token1 {
id
symbol
name
decimals
}
reserve0
reserve1
totalSupply
# Related entities
swaps(first: 10, orderBy: timestamp, orderDirection: desc) {
id
timestamp
amount0In
amount1In
amount0Out
amount1Out
amountUSD
}
}
}
Performance Best Practices
Limit Response Size
- Use
firstparameter to limit results (max typically 1000, recommended 100) - Paginate large datasets using
skipor cursor-based pagination - Avoid querying all items in large collections
Use Specific Fields
# Good - only request needed fields
query EfficientQuery {
tokens(first: 10) {
id
symbol
name
}
}
# Avoid - requesting unnecessary nested data
query IneffcientQuery {
tokens(first: 10) {
id
symbol
name
pairs {
swaps {
# This can return massive amounts of data
}
}
}
}
Use Aggregated Fields
# Good - use pre-aggregated data
query GoodAggregation($contractId: String!) {
erc721Contract(id: $contractId) {
holders # Pre-calculated count
stakedHolders # Pre-calculated count
totalSupply { value }
}
}
# Avoid - counting individual records
query BadAggregation($contractId: String!) {
erc721Tokens(where: { contract: $contractId }) {
# Counting these manually is inefficient
id
}
}
Common Query Scenarios
Latest Activity
query LatestActivity($limit: Int = 20) {
transactions(
first: $limit
orderBy: timestamp
orderDirection: desc
) {
id
timestamp
blockNumber
# ... transaction details
}
}
User Portfolio
query UserPortfolio($userAddress: String!) {
account(id: $userAddress) {
id
# ERC20 balances
erc20Balances(where: { value_gt: "0" }) {
token {
id
symbol
name
}
value
}
# ERC721 (NFT) balances
erc721Balances(where: { value_gt: "0" }) {
contract {
id
name
symbol
}
value
}
}
}
Price and Volume Analysis
query PriceVolume($pairAddress: String!, $days: Int = 7) {
pair(id: $pairAddress) {
token0 { symbol }
token1 { symbol }
token0Price
token1Price
volumeUSD
reserveUSD
# Daily historical data
pairDayData(
first: $days
orderBy: date
orderDirection: desc
) {
date
dailyVolumeUSD
reserveUSD
}
}
}
Error Handling
Common GraphQL Errors
- Field doesn't exist: Check schema with introspection
- Type mismatch: Ensure variable types match schema (String vs Int vs BigInt)
- Query too complex: Simplify nested queries or reduce
firstparameter - Timeout: Reduce query complexity or add more specific filters
Debugging Queries
Use introspection to explore the schema:
query IntrospectTypes {
__schema {
types {
name
kind
}
}
}
query IntrospectType($typeName: String!) {
__type(name: $typeName) {
name
fields {
name
type {
name
kind
}
}
}
}