Skip to main content
Graph Node provides powerful filtering and querying capabilities for precise data retrieval. This guide covers all available filter operators, sorting options, and advanced query patterns.

Filter Operators

Filters are applied using the where argument on collection queries. Each field in your entity type supports multiple filter operators.

Equality Filters

field
Value
Exact match filter. Matches entities where the field equals the specified value.
field_not
Value
Negation filter. Matches entities where the field does not equal the specified value.
query {
  tokens(where: { symbol: "ETH" }) {
    id
    name
    symbol
  }
}

Comparison Filters

Available for numeric types (Int, Int8, BigInt, BigDecimal) and Timestamp:
field_gt
Value
Greater than. Matches entities where the field is greater than the specified value.
field_gte
Value
Greater than or equal to.
field_lt
Value
Less than.
field_lte
Value
Less than or equal to.
query {
  tokens(where: {
    totalSupply_gte: "1000000000000000000"
    totalSupply_lt: "10000000000000000000"
  }) {
    id
    symbol
    totalSupply
  }
}

String Filters

String fields support various text matching operators:
field_contains
String
Case-sensitive substring match.
field_contains_nocase
String
Case-insensitive substring match.
field_not_contains
String
Does not contain substring (case-sensitive).
field_not_contains_nocase
String
Does not contain substring (case-insensitive).
field_starts_with
String
Starts with prefix (case-sensitive).
field_starts_with_nocase
String
Starts with prefix (case-insensitive).
field_not_starts_with
String
Does not start with prefix (case-sensitive).
field_not_starts_with_nocase
String
Does not start with prefix (case-insensitive).
field_ends_with
String
Ends with suffix (case-sensitive).
field_ends_with_nocase
String
Ends with suffix (case-insensitive).
query {
  tokens(where: { name_contains: "Wrapped" }) {
    id
    name
  }
}

List Filters

field_in
[Value]
Matches entities where the field value is in the provided list.
field_not_in
[Value]
Matches entities where the field value is not in the provided list.
query {
  tokens(where: {
    symbol_in: ["ETH", "WETH", "USDC", "DAI"]
  }) {
    id
    symbol
    name
  }
}

Boolean Operators

AND Operator

By default, multiple filter conditions at the same level are combined with AND:
query {
  tokens(where: {
    symbol: "ETH"
    decimals: 18
    totalSupply_gte: "1000000000000000000"
  }) {
    id
    symbol
  }
}
Explicit AND using the and operator:
query {
  tokens(where: {
    and: [
      { symbol: "ETH" }
      { decimals: 18 }
    ]
  }) {
    id
    symbol
  }
}

OR Operator

The or operator matches entities that satisfy any of the provided conditions:
query {
  tokens(where: {
    or: [
      { symbol: "ETH" }
      { symbol: "WETH" }
      { name_contains: "Ethereum" }
    ]
  }) {
    id
    symbol
    name
  }
}
Important: You cannot mix column filters with or at the same level. This is invalid:
# INVALID: Cannot mix direct filters with 'or'
query {
  tokens(where: {
    symbol: "ETH"  # ❌ Direct filter
    or: [...]      # ❌ or operator
  }) { ... }
}
Instead, wrap all conditions in or:
# VALID: All conditions inside 'or'
query {
  tokens(where: {
    or: [
      { symbol: "ETH", decimals: 18 }
      { symbol: "USDC", decimals: 6 }
    ]
  }) { ... }
}

Nested Entity Filters

Filter by related entity fields using nested filters:
type Token @entity {
  id: ID!
  symbol: String!
  owner: Account!
}

type Account @entity {
  id: ID!
  address: Bytes!
}
Query tokens by owner properties:
query {
  tokens(where: {
    owner_: {
      address: "0x1234567890123456789012345678901234567890"
    }
  }) {
    id
    symbol
    owner {
      address
    }
  }
}

Derived Field Filters

Filter parent entities by properties of derived child entities:
type Token @entity {
  id: ID!
  symbol: String!
  transfers: [Transfer!]! @derivedFrom(field: "token")
}

type Transfer @entity {
  id: ID!
  token: Token!
  amount: BigInt!
}
Find tokens with large transfers:
query {
  tokens(where: {
    transfers_: {
      amount_gte: "1000000000000000000000"
    }
  }) {
    id
    symbol
    transfers(first: 5) {
      amount
    }
  }
}

Sorting

Simple Sorting

Sort by any field using orderBy and orderDirection:
query {
  tokens(
    orderBy: totalSupply
    orderDirection: asc
    first: 10
  ) {
    id
    symbol
    totalSupply
  }
}

Child Entity Sorting

Sort by fields of related entities using double underscore notation:
query {
  transfers(
    orderBy: token__symbol
    orderDirection: asc
    first: 10
  ) {
    id
    amount
    token {
      symbol
    }
  }
}
Graph Node automatically appends id to the ORDER BY clause to ensure deterministic ordering:
  • orderBy: name becomes ORDER BY name, id
  • This guarantees consistent pagination even when the sort field has duplicate values

Pagination

Basic Pagination

Use first and skip for offset-based pagination:
query {
  tokens(first: 100, skip: 0) {
    id
    symbol
  }
}

Keyset Pagination

For better performance with large offsets, use keyset (cursor-based) pagination:
# First page
query {
  tokens(
    first: 100
    orderBy: id
    orderDirection: asc
  ) {
    id
    symbol
  }
}

# Next page - use last ID from previous result
query {
  tokens(
    first: 100
    where: { id_gt: "last_id_from_previous_page" }
    orderBy: id
    orderDirection: asc
  ) {
    id
    symbol
  }
}
Full-text search requires explicit declaration in the subgraph manifest:
# subgraph.yaml
features:
  - fullTextSearch
Define full-text fields in your schema:
type Article @entity {
  id: ID!
  title: String!
  content: String!
  search: String! @fulltext(query: "articleSearch")
}
Query using the text argument:
query {
  articleSearch(text: "ethereum blockchain") {
    id
    title
    content
  }
}

Change Block Filter

Query entities that changed at or after a specific block:
query {
  tokens(where: {
    _change_block: { number_gte: 15000000 }
  }) {
    id
    symbol
    name
  }
}
This is useful for:
  • Incremental data synchronization
  • Detecting entities modified in recent blocks
  • Change tracking and auditing

Complex Query Examples

Combine multiple filters with boolean logic:
query {
  tokens(where: {
    or: [
      {
        symbol_in: ["ETH", "WETH"]
        totalSupply_gte: "1000000000000000000000000"
      }
      {
        name_contains: "Wrapped"
        decimals: 18
      }
    ]
  }) {
    id
    symbol
    name
    totalSupply
  }
}
Filter by nested entities and sort results:
query {
  accounts(
    where: {
      tokens_: {
        totalSupply_gte: "1000000000000000000"
      }
    }
    orderBy: id
    first: 50
  ) {
    id
    address
    tokens(first: 10, orderBy: totalSupply, orderDirection: desc) {
      symbol
      totalSupply
    }
  }
}
Query entities within a specific time range:
query {
  transfers(
    where: {
      timestamp_gte: "1704067200000000"  # 2024-01-01 00:00:00 UTC
      timestamp_lt: "1706745600000000"   # 2024-02-01 00:00:00 UTC
      amount_gte: "1000000000000000000"
    }
    orderBy: timestamp
    orderDirection: desc
    first: 100
  ) {
    id
    from
    to
    amount
    timestamp
  }
}

Query Limits

Graph Node enforces configurable limits to prevent excessive resource usage:
  • Maximum first value: Default is 1000, configurable per instance
  • Maximum skip value: Default is 5000, configurable per instance
  • Query timeout: Queries that take too long are automatically cancelled
  • Query complexity: Very complex queries may be rejected
Exceeding query limits returns an error:
{
  "errors": [{
    "message": "Range argument 'first' must be between 0 and 1000"
  }]
}

Best Practices

  1. Use specific filters: Narrow down results with precise filters to reduce data transferred
  2. Limit field selection: Only query fields you need
  3. Prefer keyset pagination: For large datasets, use id_gt instead of large skip values
  4. Sort explicitly: Always specify orderBy for consistent pagination
  5. Index appropriately: Graph Node automatically indexes fields, but query patterns matter
  6. Monitor query performance: Use query execution time to optimize data access patterns

Next Steps

Build docs developers (and LLMs) love