Files
2025-11-30 08:44:39 +08:00

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 first parameter to limit results (max typically 1000, recommended 100)
  • Paginate large datasets using skip or 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

  1. Field doesn't exist: Check schema with introspection
  2. Type mismatch: Ensure variable types match schema (String vs Int vs BigInt)
  3. Query too complex: Simplify nested queries or reduce first parameter
  4. 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
      }
    }
  }
}