logo

qbjs

Guides

Filtering

Learn how to use filter operators to query your data with qbjs

Filtering allows you to retrieve only the data that matches specific conditions. qbjs supports a comprehensive set of filter operators that work across all supported databases.

Basic Filter Syntax

Filters use bracket notation in query strings:

filter[fieldName][operator]=value

For example, to find posts with a specific status:

GET /api/posts?filter[status][eq]=published

Comparison Operators

Equality Operators

OperatorDescriptionExample
eqEqual tofilter[status][eq]=active
eqiEqual to (case-insensitive)filter[name][eqi]=john
neNot equal tofilter[status][ne]=deleted
neiNot equal to (case-insensitive)filter[name][nei]=admin
// Query string
"filter[status][eq]=published"

// Parsed AST filter
{
  type: "field",
  field: "status",
  operator: "eq",
  value: "published"
}

Numeric Comparison

OperatorDescriptionExample
gtGreater thanfilter[price][gt]=100
gteGreater than or equalfilter[age][gte]=18
ltLess thanfilter[stock][lt]=10
lteLess than or equalfilter[rating][lte]=5
// Find products priced between $50 and $200
"filter[price][gte]=50&filter[price][lte]=200"

Range Operator

OperatorDescriptionExample
betweenValue is between two valuesfilter[price][between][0]=10&filter[price][between][1]=100
// Query string for between
"filter[createdAt][between][0]=2024-01-01&filter[createdAt][between][1]=2024-12-31"

// Parsed AST filter
{
  type: "field",
  field: "createdAt",
  operator: "between",
  value: ["2024-01-01", "2024-12-31"]
}

String Operators

Contains Operators

OperatorDescriptionExample
containsContains substring (case-sensitive)filter[title][contains]=typescript
containsiContains substring (case-insensitive)filter[title][containsi]=TypeScript
notContainsDoes not contain (case-sensitive)filter[content][notContains]=spam
notContainsiDoes not contain (case-insensitive)filter[content][notContainsi]=SPAM
// Find posts containing "tutorial" (case-insensitive)
"filter[title][containsi]=tutorial"

Pattern Matching

OperatorDescriptionExample
startsWithStarts with stringfilter[email][startsWith]=admin
endsWithEnds with stringfilter[email][endsWith]=@company.com
// Find users with company email addresses
"filter[email][endsWith]=@company.com"

Array Operators

OperatorDescriptionExample
inValue is in arrayfilter[status][in][0]=draft&filter[status][in][1]=review
notInValue is not in arrayfilter[role][notIn][0]=admin&filter[role][notIn][1]=superuser
// Find posts with status "draft" or "review"
"filter[status][in][0]=draft&filter[status][in][1]=review"

// Parsed AST filter
{
  type: "field",
  field: "status",
  operator: "in",
  value: ["draft", "review"]
}

Null Operators

OperatorDescriptionExample
nullValue is nullfilter[deletedAt][null]=true
notNullValue is not nullfilter[publishedAt][notNull]=true
// Find posts that have been published (publishedAt is not null)
"filter[publishedAt][notNull]=true"

Logical Operators

qbjs supports combining multiple filter conditions using logical operators.

AND Operator

Multiple filters on different fields are automatically combined with AND:

// Both conditions must be true
"filter[status][eq]=published&filter[category][eq]=tech"

For explicit AND with complex conditions:

// Explicit AND syntax
"filter[and][0][status][eq]=published&filter[and][1][featured][eq]=true"

// Parsed AST
{
  type: "logical",
  operator: "and",
  conditions: [
    { type: "field", field: "status", operator: "eq", value: "published" },
    { type: "field", field: "featured", operator: "eq", value: "true" }
  ]
}

OR Operator

Use the or operator when any condition can match:

// Either condition can be true
"filter[or][0][status][eq]=draft&filter[or][1][status][eq]=review"

// Parsed AST
{
  type: "logical",
  operator: "or",
  conditions: [
    { type: "field", field: "status", operator: "eq", value: "draft" },
    { type: "field", field: "status", operator: "eq", value: "review" }
  ]
}

NOT Operator

Negate a condition:

// Find posts that are NOT deleted
"filter[not][status][eq]=deleted"

// Parsed AST
{
  type: "logical",
  operator: "not",
  conditions: [
    { type: "field", field: "status", operator: "eq", value: "deleted" }
  ]
}

Complex Filter Examples

Combining Multiple Conditions

// Find published tech posts from 2024
const queryString = [
  "filter[status][eq]=published",
  "filter[category][eq]=tech",
  "filter[createdAt][gte]=2024-01-01"
].join("&");

Nested Logical Operators

// Find posts that are (published AND featured) OR (draft AND by admin)
"filter[or][0][and][0][status][eq]=published&filter[or][0][and][1][featured][eq]=true&filter[or][1][and][0][status][eq]=draft&filter[or][1][and][1][authorRole][eq]=admin"

Using Filters in Code

import { parse, createDrizzlePgCompiler } from '@qbjs/core';
import { posts } from './schema';

// Parse the query string
const result = parse({
  filter: {
    status: { eq: 'published' },
    category: { containsi: 'tech' }
  }
});

// Compile to Drizzle query
const compiler = createDrizzlePgCompiler();
const compiled = compiler.compile(result.ast!, posts);

// Use with Drizzle
const data = await db
  .select()
  .from(posts)
  .where(compiled.query.where);

Filter Operator Reference

OperatorDescriptionValue TypeCase Sensitive
eqEqualanyYes
eqiEqualstringNo
neNot equalanyYes
neiNot equalstringNo
gtGreater thannumber/date-
gteGreater than or equalnumber/date-
ltLess thannumber/date-
lteLess than or equalnumber/date-
inIn arrayarrayYes
notInNot in arrayarrayYes
containsContains substringstringYes
containsiContains substringstringNo
notContainsDoes not containstringYes
notContainsiDoes not containstringNo
startsWithStarts withstringYes
endsWithEnds withstringYes
nullIs nullboolean-
notNullIs not nullboolean-
betweenBetween two values[min, max]-

Best Practices

  1. Use case-insensitive operators for user input: When filtering by user-provided search terms, prefer containsi over contains.

  2. Validate filter fields: Use security configuration to restrict which fields can be filtered.

  3. Index filtered columns: Ensure database columns used in filters have appropriate indexes for performance.

  4. Limit filter complexity: Deep nesting of logical operators can impact query performance.

On this page