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