Skip to main content
Filtering allows you to retrieve only the data that matches specific conditions. The NestJS CRUD framework provides a comprehensive set of operators for building simple to complex filters.

Basic Syntax

Filters use the following format:
filter={field}||{operator}||{value}
  • field: The name of the field to filter
  • operator: The comparison operator to use
  • value: The value to compare against (optional for some operators)

Example

GET /users?filter=name||eq||John
This retrieves all users where the name equals “John”.

Comparison Operators

The framework supports both modern ($ prefixed) and deprecated operators.

Equality Operators

OperatorModernDescriptionExample
eq$eqEquals`filter=name$eqJohn`
ne$neNot equals`filter=status$neinactive`
# Find users named John
GET /users?filter=name||$eq||John

# Find users not named John
GET /users?filter=name||$ne||John

Comparison Operators

OperatorModernDescriptionExample
gt$gtGreater than`filter=age$gt18`
gte$gteGreater than or equal`filter=age$gte18`
lt$ltLess than`filter=price$lt100`
lte$lteLess than or equal`filter=price$lte100`
# Find users older than 18
GET /users?filter=age||$gt||18

# Find products under $100
GET /products?filter=price||$lte||100

String Operators

OperatorModernDescriptionExample
starts$startsStarts with`filter=name$startsJo`
ends$endsEnds with`filter=email$ends@gmail.com`
cont$contContains`filter=description$contkeyword`
excl$exclExcludes`filter=name$excltest`
# Find users whose name starts with "Jo"
GET /users?filter=name||$starts||Jo

# Find products containing "laptop" in description
GET /products?filter=description||$cont||laptop

# Find emails ending with @gmail.com
GET /users?filter=email||$ends||@gmail.com

Case-Insensitive String Operators

All string operators have case-insensitive variants with the L suffix:
OperatorDescriptionExample
$eqLEquals (case-insensitive)`filter=name$eqLjohn`
$neLNot equals (case-insensitive)`filter=name$neLjohn`
$startsLStarts with (case-insensitive)`filter=name$startsLjo`
$endsLEnds with (case-insensitive)`filter=email$endsL@gmail.com`
$contLContains (case-insensitive)`filter=description$contLlaptop`
$exclLExcludes (case-insensitive)`filter=name$exclLtest`
# Find users named "john" (case-insensitive)
GET /users?filter=name||$eqL||john
# Matches: "John", "JOHN", "john", "JoHn"

# Find products containing "LAPTOP" (case-insensitive)
GET /products?filter=description||$contL||LAPTOP
# Matches: "laptop", "Laptop", "LAPTOP"
Use case-insensitive operators ($eqL, $contL, etc.) when you want to match strings regardless of case.

Array Operators

OperatorModernDescriptionExample
in$inIn array`filter=status$inactive,pending`
notin$notinNot in array`filter=role$notinguest,banned`
between$betweenBetween values`filter=age$between18,65`
# Find users with status active or pending
GET /users?filter=status||$in||active,pending

# Find users aged between 18 and 65
GET /users?filter=age||$between||18,65

# Find users not in guest or banned roles
GET /users?filter=role||$notin||guest,banned

Case-Insensitive Array Operators

OperatorDescriptionExample
$inLIn array (case-insensitive)`filter=status$inLactive,pending`
$notinLNot in array (case-insensitive)`filter=role$notinLguest,banned`
# Find users with status "active" or "pending" (case-insensitive)
GET /users?filter=status||$inL||active,PENDING
# Matches: "Active", "PENDING", "active", "pending"

Null Operators

OperatorModernDescriptionExample
isnull$isnullIs null`filter=deletedAt$isnull`
notnull$notnullIs not null`filter=email$notnull`
# Find users that have not been deleted
GET /users?filter=deletedAt||$isnull

# Find users with email addresses
GET /users?filter=email||$notnull
Null operators do not require a value parameter. The syntax is: filter={field}||{operator}

Multiple Filters (AND)

You can apply multiple filters to create AND conditions:
# Find active users older than 18
GET /users?filter=isActive||eq||true&filter=age||gt||18
All filter conditions must be satisfied (AND logic).

OR Conditions

Use the or parameter for OR logic:
# Find users named John OR Jane
GET /users?or=name||eq||John&or=name||eq||Jane

Combining AND and OR

You can combine both filter (AND) and or parameters:
# Find active users named John OR Jane
GET /users?filter=isActive||eq||true&or=name||eq||John&or=name||eq||Jane
This translates to: isActive = true AND (name = 'John' OR name = 'Jane') For complex queries, use the s (search) parameter with JSON:
GET /users?s={"name":"John"}

With Operators

GET /users?s={"age":{"$gte":18}}

Complex OR Conditions

GET /users?s={"$or":[{"name":"John"},{"email":{"$ends":"@gmail.com"}}]}

Nested AND Conditions

GET /users?s={"name":"John","age":{"$gte":18},"isActive":true}
When using the s (search) parameter, any filter and or parameters are ignored.

Filtering Nested Fields

You can filter by nested object fields using dot notation:
# Filter by nested profile field
GET /users?filter=profile.city||eq||New York

# Filter by nested relation field
GET /posts?filter=author.name||eq||John

Type Conversion

Values are automatically parsed to the correct type:
# Number
/users?filter=age||eq||25  # value is number 25

# Boolean
/users?filter=isActive||eq||true  # value is boolean true

# Date
/users?filter=createdAt||gt||2024-01-01T00:00:00.000Z  # value is Date object

# String
/users?filter=name||eq||John  # value is string "John"

# Array
/users?filter=id||in||1,2,3  # value is array [1, 2, 3]

Practical Examples

E-commerce Filters

# Find products in a price range
GET /products?filter=price||gte||10&filter=price||lte||100

# Find products by category and in stock
GET /products?filter=category||eq||electronics&filter=stock||gt||0

# Find products with specific tags
GET /products?filter=tags||in||sale,featured,new

User Management

# Find active users created this year
GET /users?filter=isActive||eq||true&filter=createdAt||gte||2024-01-01

# Find users by role
GET /users?filter=role||in||admin,moderator

# Find unverified users
GET /users?filter=emailVerified||eq||false

Content Management

# Find published posts containing keyword
GET /posts?filter=status||eq||published&filter=title||cont||tutorial

# Find draft posts by author
GET /posts?filter=status||eq||draft&filter=authorId||eq||123

# Find posts without comments
GET /posts?filter=commentsCount||eq||0

Error Handling

Invalid filters will throw a RequestQueryException:
# Invalid operator
GET /users?filter=name||invalid||John
# Error: Invalid comparison operator

# Missing value for non-null operator
GET /users?filter=name||eq
# Error: Invalid filter value

# Invalid field format
GET /users?filter=||eq||John
# Error: Invalid field type in filter condition

Best Practices

  1. Use modern operators: Prefer $eq, $gt, etc. over deprecated operators
  2. Use case-insensitive operators: Use $eqL, $contL for user input to avoid case sensitivity issues
  3. Validate user input: Always validate and sanitize filter values from user input
  4. Index filtered fields: Add database indexes to fields commonly used in filters
  5. Combine with pagination: Always use limit when filtering to prevent large result sets
  6. Use appropriate operators: Choose the right operator for the data type (e.g., $between for ranges)

Next Steps

Sorting

Learn how to sort filtered results

Pagination

Paginate through filtered data

Relations

Filter related entities with joins

Query Parameters

Overview of all query parameters

Build docs developers (and LLMs) love