> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/graphprotocol/graph-node/llms.txt
> Use this file to discover all available pages before exploring further.

# Query Syntax and Filters

> Advanced filtering, sorting, and querying capabilities in Graph Node's GraphQL API

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

<ResponseField name="field" type="Value">
  Exact match filter. Matches entities where the field equals the specified value.
</ResponseField>

<ResponseField name="field_not" type="Value">
  Negation filter. Matches entities where the field does not equal the specified value.
</ResponseField>

<CodeGroup>
  ```graphql Equality theme={null}
  query {
    tokens(where: { symbol: "ETH" }) {
      id
      name
      symbol
    }
  }
  ```

  ```graphql Not Equals theme={null}
  query {
    tokens(where: { symbol_not: "ETH" }) {
      id
      name
      symbol
    }
  }
  ```
</CodeGroup>

### Comparison Filters

Available for numeric types (`Int`, `Int8`, `BigInt`, `BigDecimal`) and `Timestamp`:

<ResponseField name="field_gt" type="Value">
  Greater than. Matches entities where the field is greater than the specified value.
</ResponseField>

<ResponseField name="field_gte" type="Value">
  Greater than or equal to.
</ResponseField>

<ResponseField name="field_lt" type="Value">
  Less than.
</ResponseField>

<ResponseField name="field_lte" type="Value">
  Less than or equal to.
</ResponseField>

<CodeGroup>
  ```graphql Numeric Range theme={null}
  query {
    tokens(where: {
      totalSupply_gte: "1000000000000000000"
      totalSupply_lt: "10000000000000000000"
    }) {
      id
      symbol
      totalSupply
    }
  }
  ```

  ```graphql Timestamp Range theme={null}
  query {
    transfers(where: {
      timestamp_gte: "1704164640000000"
      timestamp_lt: "1704251040000000"
    }) {
      id
      from
      to
      timestamp
    }
  }
  ```
</CodeGroup>

### String Filters

String fields support various text matching operators:

<ResponseField name="field_contains" type="String">
  Case-sensitive substring match.
</ResponseField>

<ResponseField name="field_contains_nocase" type="String">
  Case-insensitive substring match.
</ResponseField>

<ResponseField name="field_not_contains" type="String">
  Does not contain substring (case-sensitive).
</ResponseField>

<ResponseField name="field_not_contains_nocase" type="String">
  Does not contain substring (case-insensitive).
</ResponseField>

<ResponseField name="field_starts_with" type="String">
  Starts with prefix (case-sensitive).
</ResponseField>

<ResponseField name="field_starts_with_nocase" type="String">
  Starts with prefix (case-insensitive).
</ResponseField>

<ResponseField name="field_not_starts_with" type="String">
  Does not start with prefix (case-sensitive).
</ResponseField>

<ResponseField name="field_not_starts_with_nocase" type="String">
  Does not start with prefix (case-insensitive).
</ResponseField>

<ResponseField name="field_ends_with" type="String">
  Ends with suffix (case-sensitive).
</ResponseField>

<ResponseField name="field_ends_with_nocase" type="String">
  Ends with suffix (case-insensitive).
</ResponseField>

<CodeGroup>
  ```graphql Contains theme={null}
  query {
    tokens(where: { name_contains: "Wrapped" }) {
      id
      name
    }
  }
  ```

  ```graphql Case-Insensitive Search theme={null}
  query {
    tokens(where: { symbol_contains_nocase: "eth" }) {
      id
      symbol
    }
  }
  ```

  ```graphql Prefix Match theme={null}
  query {
    tokens(where: { name_starts_with: "Uniswap" }) {
      id
      name
    }
  }
  ```
</CodeGroup>

### List Filters

<ResponseField name="field_in" type="[Value]">
  Matches entities where the field value is in the provided list.
</ResponseField>

<ResponseField name="field_not_in" type="[Value]">
  Matches entities where the field value is not in the provided list.
</ResponseField>

<CodeGroup>
  ```graphql In List theme={null}
  query {
    tokens(where: {
      symbol_in: ["ETH", "WETH", "USDC", "DAI"]
    }) {
      id
      symbol
      name
    }
  }
  ```

  ```graphql Not In List theme={null}
  query {
    transfers(where: {
      from_not_in: ["0x0000000000000000000000000000000000000000"]
    }) {
      id
      from
      to
      amount
    }
  }
  ```
</CodeGroup>

## Boolean Operators

### AND Operator

By default, multiple filter conditions at the same level are combined with AND:

```graphql theme={null}
query {
  tokens(where: {
    symbol: "ETH"
    decimals: 18
    totalSupply_gte: "1000000000000000000"
  }) {
    id
    symbol
  }
}
```

Explicit AND using the `and` operator:

```graphql theme={null}
query {
  tokens(where: {
    and: [
      { symbol: "ETH" }
      { decimals: 18 }
    ]
  }) {
    id
    symbol
  }
}
```

### OR Operator

The `or` operator matches entities that satisfy any of the provided conditions:

```graphql theme={null}
query {
  tokens(where: {
    or: [
      { symbol: "ETH" }
      { symbol: "WETH" }
      { name_contains: "Ethereum" }
    ]
  }) {
    id
    symbol
    name
  }
}
```

<Warning>
  **Important:** You cannot mix column filters with `or` at the same level. This is invalid:

  ```graphql theme={null}
  # INVALID: Cannot mix direct filters with 'or'
  query {
    tokens(where: {
      symbol: "ETH"  # ❌ Direct filter
      or: [...]      # ❌ or operator
    }) { ... }
  }
  ```

  Instead, wrap all conditions in `or`:

  ```graphql theme={null}
  # VALID: All conditions inside 'or'
  query {
    tokens(where: {
      or: [
        { symbol: "ETH", decimals: 18 }
        { symbol: "USDC", decimals: 6 }
      ]
    }) { ... }
  }
  ```
</Warning>

## Nested Entity Filters

Filter by related entity fields using nested filters:

```graphql theme={null}
type Token @entity {
  id: ID!
  symbol: String!
  owner: Account!
}

type Account @entity {
  id: ID!
  address: Bytes!
}
```

Query tokens by owner properties:

```graphql theme={null}
query {
  tokens(where: {
    owner_: {
      address: "0x1234567890123456789012345678901234567890"
    }
  }) {
    id
    symbol
    owner {
      address
    }
  }
}
```

### Derived Field Filters

Filter parent entities by properties of derived child entities:

```graphql theme={null}
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:

```graphql theme={null}
query {
  tokens(where: {
    transfers_: {
      amount_gte: "1000000000000000000000"
    }
  }) {
    id
    symbol
    transfers(first: 5) {
      amount
    }
  }
}
```

## Sorting

### Simple Sorting

Sort by any field using `orderBy` and `orderDirection`:

<CodeGroup>
  ```graphql Ascending theme={null}
  query {
    tokens(
      orderBy: totalSupply
      orderDirection: asc
      first: 10
    ) {
      id
      symbol
      totalSupply
    }
  }
  ```

  ```graphql Descending theme={null}
  query {
    tokens(
      orderBy: totalSupply
      orderDirection: desc
      first: 10
    ) {
      id
      symbol
      totalSupply
    }
  }
  ```
</CodeGroup>

### Child Entity Sorting

Sort by fields of related entities using double underscore notation:

```graphql theme={null}
query {
  transfers(
    orderBy: token__symbol
    orderDirection: asc
    first: 10
  ) {
    id
    amount
    token {
      symbol
    }
  }
}
```

<Note>
  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
</Note>

## Pagination

### Basic Pagination

Use `first` and `skip` for offset-based pagination:

<CodeGroup>
  ```graphql Page 1 theme={null}
  query {
    tokens(first: 100, skip: 0) {
      id
      symbol
    }
  }
  ```

  ```graphql Page 2 theme={null}
  query {
    tokens(first: 100, skip: 100) {
      id
      symbol
    }
  }
  ```

  ```graphql Page 3 theme={null}
  query {
    tokens(first: 100, skip: 200) {
      id
      symbol
    }
  }
  ```
</CodeGroup>

### Keyset Pagination

For better performance with large offsets, use keyset (cursor-based) pagination:

```graphql theme={null}
# 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

Full-text search requires explicit declaration in the subgraph manifest:

```yaml theme={null}
# subgraph.yaml
features:
  - fullTextSearch
```

Define full-text fields in your schema:

```graphql theme={null}
type Article @entity {
  id: ID!
  title: String!
  content: String!
  search: String! @fulltext(query: "articleSearch")
}
```

Query using the `text` argument:

```graphql theme={null}
query {
  articleSearch(text: "ethereum blockchain") {
    id
    title
    content
  }
}
```

## Change Block Filter

Query entities that changed at or after a specific block:

```graphql theme={null}
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

<Accordion title="Multi-Condition Filtering">
  Combine multiple filters with boolean logic:

  ```graphql theme={null}
  query {
    tokens(where: {
      or: [
        {
          symbol_in: ["ETH", "WETH"]
          totalSupply_gte: "1000000000000000000000000"
        }
        {
          name_contains: "Wrapped"
          decimals: 18
        }
      ]
    }) {
      id
      symbol
      name
      totalSupply
    }
  }
  ```
</Accordion>

<Accordion title="Nested Filtering with Sorting">
  Filter by nested entities and sort results:

  ```graphql theme={null}
  query {
    accounts(
      where: {
        tokens_: {
          totalSupply_gte: "1000000000000000000"
        }
      }
      orderBy: id
      first: 50
    ) {
      id
      address
      tokens(first: 10, orderBy: totalSupply, orderDirection: desc) {
        symbol
        totalSupply
      }
    }
  }
  ```
</Accordion>

<Accordion title="Time-Range Queries">
  Query entities within a specific time range:

  ```graphql theme={null}
  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
    }
  }
  ```
</Accordion>

## 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

<Warning>
  Exceeding query limits returns an error:

  ```json theme={null}
  {
    "errors": [{
      "message": "Range argument 'first' must be between 0 and 1000"
    }]
  }
  ```
</Warning>

## 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

* Explore [aggregation queries](/api/aggregations) for timeseries analytics
* Learn about [time-travel queries](/api/time-travel) for historical data
* Review [GraphQL API overview](/api/graphql-api) for basic concepts
