Querying
Every adapter exposes the same _find query language — a FeathersJS-style object that
drives filtering, pagination, sorting, field selection and relation loading. The same shape
works in code and as an HTTP query string.
const result = await service._find({
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
$sort: { createdAt: -1 },
$limit: 20,
});GET /products?status[$in][]=active&status[$in][]=pending&price[$gte]=10&$sort[createdAt]=-1&$limit=20The response is a paginated envelope:
interface PaginatedResponse<D> {
total: number;
$limit: number;
$skip: number;
data: D[];
}Queries by database
The _find API is the same everywhere, but relation loading and case-insensitive matching
differ slightly. Pick your database to see the exact example:
Adapter: Prisma or TypeORM
await service._find({
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
name: { $iLike: 'phone' }, // case-insensitive match
$include: { reviews: true }, // eager-load relations
$sort: { createdAt: -1 },
$limit: 20,
});await service._find({
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
name: { $iLike: 'phone' }, // case-insensitive match
$include: { reviews: true }, // eager-load relations
$sort: { createdAt: -1 },
$limit: 20,
});await service._find({
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
name: { $iLike: 'phone' }, // case-insensitive match
$include: { reviews: true }, // eager-load relations
$sort: { createdAt: -1 },
$limit: 20,
});await service._find({
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
name: { $regex: 'phone', $options: 'i' }, // pattern match
$populate: 'reviews', // populate relations
$sort: { createdAt: -1 },
$limit: 20,
});Special parameters
| Parameter | Default | Purpose |
|---|---|---|
$limit | 20 | Maximum documents to return |
$skip | 0 | Offset for pagination |
$sort | — | Sort map, e.g. { createdAt: -1 } (-1 desc, 1 asc) |
$select | — | Project a subset of fields |
$populate | — | Mongoose — populate relations |
$include | — | Prisma / TypeORM — eager-load relations |
await service._find({
$select: ['name', 'price'],
$sort: { createdAt: -1 },
$limit: 10,
$skip: 20,
});Operators
Filter values can be plain (equality) or an operator object. The operators below are available on every adapter (Prisma and TypeORM share the FeathersJS set; Mongoose maps to native MongoDB operators).
| Operator | Meaning |
|---|---|
$eq / $ne | Equal / not equal |
$gt / $gte | Greater than / greater-or-equal |
$lt / $lte | Less than / less-or-equal |
$in / $nin | In / not in a list |
$like / $notLike | Case-sensitive pattern match |
$iLike / $notILike | Case-insensitive pattern match |
$or / $and | Logical combinators |
$regex | Regular expression (Mongoose) |
await service._find({
price: { $gte: 10, $lte: 100 },
name: { $iLike: 'phone' },
$or: [{ category: 'audio' }, { brand: 'acme' }],
});Relations
Use $populate on Mongoose and $include on Prisma / TypeORM:
await catsService._find({ $populate: 'owner' });await catsService._find({ $include: { owner: true } });Case-insensitive matching differs by database.
$iLikeis fully supported on PostgreSQL; MySQL is case-insensitive by default depending on collation; SQLite has no built-in case-insensitiveLIKEfor non-ASCII text.
Calling the API over HTTP
The same query object works as a URL query string. Serialise the nested operators with
qs — it matches the parser configured by
NestExtendedModule.forRoot({ queryParser }) on the server.
import qs from 'qs';
const query = {
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
$sort: { createdAt: -1 },
$limit: 20,
};
const search = qs.stringify(query, { encodeValuesOnly: true });
// status[$in][0]=active&status[$in][1]=pending&price[$gte]=10&price[$lte]=100&$sort[createdAt]=-1&$limit=20fetch
const res = await fetch(`/products?${search}`);
const { total, data } = await res.json();Axios
Pass the query object as params and let qs serialise it so the nested operators survive:
import axios from 'axios';
import qs from 'qs';
const api = axios.create({
baseURL: '/api',
paramsSerializer: (params) => qs.stringify(params, { encodeValuesOnly: true }),
});
const { data } = await api.get('/products', {
params: {
status: { $in: ['active', 'pending'] },
price: { $gte: 10, $lte: 100 },
$sort: { createdAt: -1 },
$limit: 20,
},
});
// data => { total, $limit, $skip, data: [...] }