The RequestQueryBuilder class provides a fluent, chainable API for building complex queries from your frontend application. It generates properly formatted query strings that the NestJS CRUD backend can parse and execute.
Installation
The RequestQueryBuilder is part of the @nestjsx/crud-request package:
npm install @nestjsx/crud-request
Basic Usage
Import the builder
import { RequestQueryBuilder } from '@nestjsx/crud-request' ;
Create a new instance
const qb = RequestQueryBuilder . create ();
Chain methods and generate query string
const queryString = qb
. select ([ 'id' , 'name' , 'email' ])
. setFilter ({ field: 'isActive' , operator: '$eq' , value: true })
. setLimit ( 10 )
. query ();
Creating a Query Builder
Default Constructor
Create a new instance with default configuration:
const qb = RequestQueryBuilder . create ();
From Parameters Object
Create and configure in one step using a parameters object:
const qb = RequestQueryBuilder . create ({
fields: [ 'id' , 'name' , 'email' ],
filter: [{ field: 'age' , operator: '$gte' , value: 18 }],
sort: [{ field: 'name' , order: 'ASC' }],
limit: 20 ,
page: 1 ,
});
const queryString = qb . query ();
The create() method with parameters internally calls select(), setFilter(), sortBy(), and other methods based on the provided configuration.
Selecting Fields
Control which fields are returned in the response:
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' , 'email' , 'createdAt' ]);
Example: Select Specific Fields
Example: Select from Nested Relations
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' , 'email' ]);
// Generates: fields=id,name,email
Filtering Data
Single Filter
Apply a single filter condition:
const qb = RequestQueryBuilder . create ()
. setFilter ({ field: 'status' , operator: '$eq' , value: 'active' });
// Generates: filter=status||$eq||active
Multiple Filters (AND)
Multiple filters are combined with AND logic:
const qb = RequestQueryBuilder . create ()
. setFilter ([
{ field: 'status' , operator: '$eq' , value: 'active' },
{ field: 'age' , operator: '$gte' , value: 18 },
{ field: 'role' , operator: '$ne' , value: 'guest' },
]);
// All conditions must be true
Array Notation
Use array notation for more concise syntax:
const qb = RequestQueryBuilder . create ()
. setFilter ([ 'status' , '$eq' , 'active' ]);
// Equivalent to:
// .setFilter({ field: 'status', operator: '$eq', value: 'active' })
OR Filters
Use setOr() for OR logic:
const qb = RequestQueryBuilder . create ()
. setOr ([
{ field: 'role' , operator: '$eq' , value: 'admin' },
{ field: 'role' , operator: '$eq' , value: 'moderator' },
]);
// Generates: or=role||$eq||admin&or=role||$eq||moderator
Combining AND and OR
const qb = RequestQueryBuilder . create ()
. setFilter ({ field: 'status' , operator: '$eq' , value: 'active' })
. setOr ([
{ field: 'role' , operator: '$eq' , value: 'admin' },
{ field: 'role' , operator: '$eq' , value: 'moderator' },
]);
// (status = 'active') AND (role = 'admin' OR role = 'moderator')
Comparison Operators
Equality
Comparison
String Matching
Arrays and Nulls
Range
RequestQueryBuilder . create ()
. setFilter ({ field: 'id' , operator: '$eq' , value: 1 });
// Equals
RequestQueryBuilder . create ()
. setFilter ({ field: 'status' , operator: '$ne' , value: 'deleted' });
// Not equals
Case-insensitive operators are available by adding ‘L’ suffix: $eqL, $neL, $startsL, $endsL, $contL, $exclL, $inL, $notinL
Advanced Search
Use the search() method for complex nested conditions:
const qb = RequestQueryBuilder . create ()
. search ({
$or: [
{ name: { $cont: 'john' } },
{ email: { $cont: 'john' } },
],
});
// Search for 'john' in name OR email
Complex AND/OR
Multiple Operators
const qb = RequestQueryBuilder . create ()
. search ({
status: 'active' ,
$or: [
{ role: 'admin' },
{
$and: [
{ role: 'user' },
{ verified: true },
],
},
],
});
When using search(), any filters set with setFilter() or setOr() will be ignored. The search parameter takes precedence.
Joining Relations
Basic Join
Load related entities:
const qb = RequestQueryBuilder . create ()
. setJoin ({ field: 'profile' })
. setJoin ({ field: 'posts' });
// Generates: join=profile&join=posts
Join with Selected Fields
Control which fields are loaded from the relation:
const qb = RequestQueryBuilder . create ()
. setJoin ({
field: 'profile' ,
select: [ 'id' , 'avatar' , 'bio' ]
});
// Generates: join=profile||id,avatar,bio
Multiple Joins
const qb = RequestQueryBuilder . create ()
. setJoin ([
{ field: 'profile' , select: [ 'id' , 'avatar' ] },
{ field: 'posts' , select: [ 'id' , 'title' , 'createdAt' ] },
{ field: 'posts.comments' }, // Nested relation
]);
Array Notation for Joins
const qb = RequestQueryBuilder . create ()
. setJoin ([ 'profile' , [ 'id' , 'avatar' , 'bio' ]]);
// Equivalent to:
// .setJoin({ field: 'profile', select: ['id', 'avatar', 'bio'] })
Sorting Results
Single Sort
const qb = RequestQueryBuilder . create ()
. sortBy ({ field: 'createdAt' , order: 'DESC' });
// Generates: sort=createdAt,DESC
Multiple Sorts
const qb = RequestQueryBuilder . create ()
. sortBy ([
{ field: 'status' , order: 'ASC' },
{ field: 'createdAt' , order: 'DESC' },
]);
// Sort by status first, then by createdAt
Array Notation for Sorting
const qb = RequestQueryBuilder . create ()
. sortBy ([ 'name' , 'ASC' ]);
// Equivalent to:
// .sortBy({ field: 'name', order: 'ASC' })
Limit and Offset
const qb = RequestQueryBuilder . create ()
. setLimit ( 20 )
. setOffset ( 40 );
// Get 20 items starting from position 40
const qb = RequestQueryBuilder . create ()
. setLimit ( 20 )
. setPage ( 3 );
// Get page 3 with 20 items per page
When using setPage(), the offset is automatically calculated as (page - 1) * limit.
Cache Control
Reset Cache
Force a fresh query bypassing any server-side cache:
const qb = RequestQueryBuilder . create ()
. resetCache ();
// Generates: cache=0
Soft Deletes
Include soft-deleted records in results:
const qb = RequestQueryBuilder . create ()
. setIncludeDeleted ( 1 );
// Generates: include_deleted=1
Complete Example
Here’s a comprehensive example combining multiple features:
import { RequestQueryBuilder } from '@nestjsx/crud-request' ;
const qb = RequestQueryBuilder . create ()
// Select specific fields
. select ([ 'id' , 'name' , 'email' , 'createdAt' ])
// Join relations with specific fields
. setJoin ([
{ field: 'profile' , select: [ 'id' , 'avatar' , 'bio' ] },
{ field: 'posts' , select: [ 'id' , 'title' , 'publishedAt' ] },
])
// Filter conditions (AND)
. setFilter ([
{ field: 'isActive' , operator: '$eq' , value: true },
{ field: 'age' , operator: '$gte' , value: 18 },
])
// OR conditions
. setOr ([
{ field: 'role' , operator: '$eq' , value: 'admin' },
{ field: 'role' , operator: '$eq' , value: 'moderator' },
])
// Sorting
. sortBy ([
{ field: 'createdAt' , order: 'DESC' },
{ field: 'name' , order: 'ASC' },
])
// Pagination
. setLimit ( 20 )
. setPage ( 1 )
// Generate query string
. query ();
// Use with your HTTP client
const response = await fetch ( `/api/users? ${ queryString } ` );
Using with HTTP Clients
Fetch API
Axios
React Query
Angular HttpClient
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' ])
. setFilter ({ field: 'isActive' , operator: '$eq' , value: true })
. setLimit ( 10 );
const response = await fetch ( `/api/users? ${ qb . query () } ` );
const data = await response . json ();
Configuration
Global Options
Configure the builder globally for your application:
import { RequestQueryBuilder } from '@nestjsx/crud-request' ;
RequestQueryBuilder . setOptions ({
delim: '||' , // Delimiter for query parts
delimStr: ',' , // Delimiter for arrays
paramNamesMap: {
fields: [ 'fields' , 'select' ],
filter: 'filter' ,
or: 'or' ,
join: 'join' ,
sort: 'sort' ,
limit: [ 'limit' , 'per_page' ],
offset: 'offset' ,
page: 'page' ,
cache: 'cache' ,
includeDeleted: 'include_deleted' ,
},
});
Custom Parameter Names
If your API uses different parameter names:
RequestQueryBuilder . setOptions ({
paramNamesMap: {
fields: 'select' ,
filter: 'where' ,
limit: 'take' ,
offset: 'skip' ,
},
});
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' ])
. setLimit ( 10 );
// Generates: select=id,name&take=10
Accessing Query Object
Access the raw query object before converting to string:
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' ])
. setFilter ({ field: 'status' , operator: '$eq' , value: 'active' });
console . log ( qb . queryObject );
// {
// fields: 'id,name',
// filter: ['status||$eq||active']
// }
Query String Generation
The query() method generates the final URL query string:
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' ])
. setFilter ({ field: 'status' , operator: '$eq' , value: 'active' });
// URL encoded (default)
const encoded = qb . query ();
// fields=id%2Cname&filter=status%7C%7C%24eq%7C%7Cactive
// Without encoding
const notEncoded = qb . query ( false );
// fields=id,name&filter=status||$eq||active
The generated query string is also stored in the queryString property: qb.queryString
TypeScript Types
The builder is fully typed for TypeScript users:
import {
RequestQueryBuilder ,
QueryFilter ,
QueryJoin ,
QuerySort ,
CondOperator ,
CreateQueryParams ,
} from '@nestjsx/crud-request' ;
// Typed filter
const filter : QueryFilter = {
field: 'status' ,
operator: CondOperator . EQUALS , // or '$eq'
value: 'active' ,
};
// Typed join
const join : QueryJoin = {
field: 'profile' ,
select: [ 'id' , 'avatar' ],
};
// Typed sort
const sort : QuerySort = {
field: 'createdAt' ,
order: 'DESC' ,
};
// Use with builder
const qb = RequestQueryBuilder . create ()
. setFilter ( filter )
. setJoin ( join )
. sortBy ( sort );
Best Practices
Reusable Query Builders : Create factory functions for common queries
function createActiveUsersQuery ( page : number ) {
return RequestQueryBuilder . create ()
. select ([ 'id' , 'name' , 'email' ])
. setFilter ({ field: 'isActive' , operator: '$eq' , value: true })
. sortBy ({ field: 'name' , order: 'ASC' })
. setLimit ( 20 )
. setPage ( page );
}
Type-Safe Filters : Use TypeScript enums for operators
import { CondOperator } from '@nestjsx/crud-request' ;
const qb = RequestQueryBuilder . create ()
. setFilter ({
field: 'status' ,
operator: CondOperator . EQUALS ,
value: 'active'
});
Dynamic Queries : Build queries based on user input
function buildUserQuery ( options : {
search ?: string ;
role ?: string ;
page ?: number ;
}) {
const qb = RequestQueryBuilder . create ()
. select ([ 'id' , 'name' , 'email' , 'role' ]);
if ( options . search ) {
qb . search ({
$or: [
{ name: { $cont: options . search } },
{ email: { $cont: options . search } },
],
});
}
if ( options . role ) {
qb . setFilter ({ field: 'role' , operator: '$eq' , value: options . role });
}
if ( options . page ) {
qb . setPage ( options . page ). setLimit ( 20 );
}
return qb . query ();
}
Next Steps
Query String Format Learn about the query string format and parameters
Controllers Set up CRUD controllers to handle these queries