Installation
Requires Node.js 18+.
npm install mongo-query-toolsBasic Usage
Pass HTTP-shaped query params and a configuration object — you get a filter, sort, page, limit, and skip ready for MongoDB Driver or Mongoose.
import { buildMongoQuery } from "mongo-query-tools";
const options = buildMongoQuery(
req.query as Record<string, string | string[] | undefined>,
{
searchableFields: ["name", "email"],
allowedFilters: ["status", "role"],
allowedSorts: ["createdAt", "name"],
defaultFilters: { isDeleted: false },
defaultSort: "-createdAt",
maxLimit: 100,
defaultPage: 1,
defaultLimit: 10,
},
);Config Options
searchableFieldsApplied to case-insensitive substring search (OR combination).
allowedFiltersAllow-list for filter keys originating from query params.
allowedSortsField names allowed in sort tokens (omit + / - prefixes from this array).
defaultFiltersAlways merged. Unexpected query keys do not erase these predicates.
defaultSortUsed when sort is missing or invalid (same string syntax: field asc, -field desc).
maxLimitClamps resolved limit.
defaultPage, defaultLimitFallbacks when pagination params absent or malformed. defaultLimit honours maxLimit.
conditionalFilters / conditionalFilterBranching merge via when / filter — later merges win on key clashes (Object.assign).
Conditional Filters
Layer tenancy or auth predicates without stuffing framework globals into the parser. when and filter receive the identical query forwarded to buildMongoQuery.
import { buildMongoQuery, type QueryParams } from "mongo-query-tools";
type AppQuery = QueryParams & { mode?: string };
const options = buildMongoQuery(req.query as AppQuery, {
defaultFilters: { isDeleted: false },
searchableFields: ["name", "email"],
allowedFilters: ["role"],
conditionalFilters: [
{
when: (query) => query.mode === "personal",
filter: () => ({ ownerId: "current-user" }),
},
],
});Reserved Query Keys
Parsed as controls — never surfaced as standalone filter props even if accidentally listed inside allowedFilters.
- page
- limit
- skip
- sort
- search
Sorting Format
Comma-separated segments. Prefix with - for descending, + for explicit ascending, or omit the prefix for ascending shorthand.
| Query | Sort |
|---|---|
| name | { name: 1 } |
| -createdAt | { createdAt: -1 } |
| -createdAt,name | { createdAt: -1, name: 1 } |
If any segment violates allowedSorts, the entire sort clause is discarded and defaultSort resumes when present.
Pagination Behavior
- •
page≥ 1; else defaultPage (fallback 1) applies. - •
limit≥ 1; else defaultLimit (fallback 10) then clamps through maxLimit. - •Present
skipoverrides canonical(page − 1) × limit.
TypeScript Exports
Consume whatever your bundler tree-shakes from the barrel:
import { buildMongoQuery } from "mongo-query-tools";
import type {
BuildMongoQueryConfig,
BuildMongoQueryResult,
ConditionalFilterQuery,
ConditionalFilterRule,
QueryParams,
SortSpec,
} from "mongo-query-tools";