GraphQL Filtering¶
Verified by tests
FilterConventionTests, QueryExecutionTests — library CI run #31657041675 (2026-08-13)
Whizbang's HotChocolate integration provides powerful filtering capabilities for PerspectiveRow<T> data using the standard HotChocolate filtering syntax.
Basic Filtering¶
Filter on data properties using the where argument:
{
orders(where: { data: { status: { eq: "Completed" } } }) {
nodes {
data {
customerName
status
}
}
}
}
Filter Operators¶
String Operators¶
# Exact match
# Exact match
where: { data: { customerName: { eq: "Alice" } } }
# Not equal
where: { data: { customerName: { neq: "Bob" } } }
# Contains
where: { data: { customerName: { contains: "Corp" } } }
# Starts with
where: { data: { customerName: { startsWith: "Acme" } } }
# Ends with
where: { data: { customerName: { endsWith: "Inc" } } }
# In list
where: { data: { status: { in: ["Pending", "Processing"] } } }
# Not in list
where: { data: { status: { nin: ["Cancelled", "Refunded"] } } }
Numeric Operators¶
# Equal
# Equal
where: { data: { totalAmount: { eq: 100.00 } } }
# Greater than
where: { data: { totalAmount: { gt: 50.00 } } }
# Greater than or equal
where: { data: { totalAmount: { gte: 100.00 } } }
# Less than
where: { data: { totalAmount: { lt: 1000.00 } } }
# Less than or equal
where: { data: { totalAmount: { lte: 500.00 } } }
# Range (between)
where: {
and: [
{ data: { totalAmount: { gte: 100.00 } } }
{ data: { totalAmount: { lte: 500.00 } } }
]
}
Date/Time Operators¶
# Exact date
# Exact date
where: { data: { createdAt: { eq: "2024-01-15T00:00:00Z" } } }
# After date
where: { data: { createdAt: { gt: "2024-01-01T00:00:00Z" } } }
# Before date
where: { data: { createdAt: { lt: "2024-12-31T23:59:59Z" } } }
# Date range
where: {
and: [
{ data: { createdAt: { gte: "2024-01-01T00:00:00Z" } } }
{ data: { createdAt: { lt: "2024-02-01T00:00:00Z" } } }
]
}
Boolean Operators¶
```graphql } }" description="where: data: isActive: eq: true } } }" category="Apis" difficulty="BEGINNER" tags=["Apis", "Graphql", "GRAPHQL"]} where: { data: { isActive: { eq: true } } } where: { data: { isDeleted: { eq: false } } }
### Null Checks
**# Is null**
```graphql
# Is null
where: { data: { deletedAt: { eq: null } } }
# Is not null
where: { data: { deletedAt: { neq: null } } }
Logical Operators¶
AND (Implicit)¶
Multiple conditions at the same level are AND'd together:
{
orders(where: {
data: {
status: { eq: "Completed" }
totalAmount: { gte: 100.00 }
}
}) {
nodes { ... }
}
}
AND (Explicit)¶
{
orders(where: {
and: [
{ data: { status: { eq: "Completed" } } }
{ data: { totalAmount: { gte: 100.00 } } }
{ data: { customerName: { contains: "Corp" } } }
]
}) {
nodes { ... }
}
}
OR¶
{
orders(where: {
or: [
{ data: { status: { eq: "Completed" } } }
{ data: { status: { eq: "Shipped" } } }
]
}) {
nodes { ... }
}
}
Complex Combinations¶
{
orders(where: {
and: [
{ data: { totalAmount: { gte: 100.00 } } }
{
or: [
{ data: { status: { eq: "Completed" } } }
{ data: { status: { eq: "Shipped" } } }
]
}
]
}) {
nodes { ... }
}
}
Filtering on System Fields¶
Filter on PerspectiveRow system fields:
# By ID
# By ID
{
orders(where: { id: { eq: "550e8400-e29b-41d4-a716-446655440000" } }) {
nodes { ... }
}
}
# By version
{
orders(where: { version: { gte: 2 } }) {
nodes { ... }
}
}
# By creation date
{
orders(where: { createdAt: { gte: "2024-01-01T00:00:00Z" } }) {
nodes { ... }
}
}
Filtering on Metadata¶
When metadata is exposed (scope includes Metadata):
{
orders(where: {
metadata: {
eventType: { eq: "OrderCreated" }
}
}) {
nodes {
metadata {
eventType
correlationId
}
}
}
}
Filtering on Scope¶
When scope is exposed (scope includes Scope):
{
adminOrders(where: {
scope: {
tenantId: { eq: "tenant-123" }
}
}) {
nodes {
scope {
tenantId
userId
}
}
}
}
Filtering with Variables¶
Use GraphQL variables for dynamic filtering:
query GetOrders($status: String!, $minAmount: Decimal!)
query GetOrders($status: String!, $minAmount: Decimal!) {
orders(where: {
and: [
{ data: { status: { eq: $status } } }
{ data: { totalAmount: { gte: $minAmount } } }
]
}) {
nodes {
data {
customerName
status
totalAmount
}
}
}
}
Variables: Filtering with Variables
Performance Considerations¶
- Index your filter columns - Ensure database indexes exist for commonly filtered fields
- Avoid wide OR clauses - Multiple OR conditions can prevent index usage
- Use paging - Always combine filtering with paging for large datasets
- Project only needed fields - GraphQL projection optimizes the SQL query