How to Use Complex Where Queries with the _where Parameter in JSON Server
JSON Server supports advanced filtering through the _where query parameter, which accepts a JSON object defining field-level operators like gt, lt, contains, and logical or conditions to filter resources with precision.
The _where parameter transforms JSON Server from a simple REST mock into a queryable database backend. By leveraging the implementation found in src/parse-where.ts and src/matches-where.ts, you can construct complex filter expressions that handle numeric ranges, string patterns, list membership, and nested logical operations.
How the _where Parameter Works
When you append ?_where= to a JSON Server endpoint, the engine processes your request through three distinct phases:
Step 1: Parsing the Query String
The src/parse-where.ts module splits each key in the _where JSON into a path and an operator. For example, views:gt becomes the path views with operator gt, while name_lt is parsed as path name with operator lt. The parser also coerces values to appropriate types (numbers, booleans, or strings) based on the context.
Step 2: Building the Where Object
Using the internal setPathOp function, JSON Server constructs a nested "where" object where operators become sub-properties of their respective fields. For instance, {views:{gt:100}} represents "views greater than 100". This function specifically handles the in operator by converting comma-separated strings into arrays for list-based filtering.
Step 3: Matching Records
The src/matches-where.ts file evaluates each resource against the parsed where object. It references the operator definitions in src/where-operators.ts (which includes lt, lte, gt, gte, eq, ne, in, contains, startsWith, endsWith, and or) and applies them with short-circuit logic. If a field contains an object, the matcher recurses, enabling deep nesting for complex document structures.
Supported Operators
JSON Server recognizes the following operators within _where query objects:
| Operator | Meaning | Example Usage |
|---|---|---|
lt / lte |
Less than / Less than or equal | price:lt=10 |
gt / gte |
Greater than / Greater than or equal | views:gt=100 |
eq / ne |
Equal / Not equal | status:eq=active |
in |
Value exists in list (comma-separated) | category:in=books,movies |
contains |
Substring match (case-insensitive) | title:contains=react |
startsWith / endsWith |
Prefix / Suffix match | name:startsWith=Al |
or |
Logical OR of multiple conditions | {"or":[{"views":{"gt":1000}},{"published":{"eq":false}}]} |
Practical Examples
Basic Numeric Filters
Filter posts with more than 100 views using the gt operator:
GET /posts?_where={"views":{"gt":100}}
This parses to { views: { gt: 100 } } and returns only records where the views field exceeds 100.
String Operators
Search for posts containing "json" anywhere in the title:
GET /posts?_where={"title":{"contains":"json"}}
Match authors whose names start with "A" using nested object notation:
GET /posts?_where={"author":{"name":{"startsWith":"A"}}}
List Filters with in
Retrieve posts in specific categories by providing a comma-separated list:
GET /posts?_where={"category":{"in":"news,sports"}}
The parser converts the string "news,sports" into an array ["news", "sports"] for the in operator evaluation.
Logical OR Queries
Combine conditions where posts either have high view counts OR author names alphabetically before "m":
GET /posts?_where={"or":[{"views":{"gt":1000}},{"author":{"name":{"lt":"m"}}}]}
The or operator accepts an array of filter objects, matching records that satisfy at least one condition.
Nested and Compound Filters
Filter for posts with authors aged 30 or older whose names contain "smith", where the post is also published:
GET /posts?_where={"author":{"age":{"gte":30},"name":{"contains":"smith"}},"published":true}
This demonstrates deep nesting (author object with multiple fields) combined with top-level boolean fields.
Key Implementation Files
Understanding these source files helps debug complex queries and extend functionality:
| File | Role | Location |
|---|---|---|
src/where-operators.ts |
Declares supported operators (lt, gt, contains, etc.) and type guards |
src/where-operators.ts |
src/parse-where.ts |
Parses query strings into structured where objects, handles in array conversion |
src/parse-where.ts |
src/matches-where.ts |
Evaluates resources against parsed where objects with recursive matching | src/matches-where.ts |
README.md |
User-facing documentation for the _where API |
README.md |
These modules work sequentially: parsing converts HTTP parameters to JavaScript objects, then matching applies operator logic against your JSON database records.
Summary
- The
_whereparameter accepts a JSON object defining field operators for advanced filtering in JSON Server. - Supported operators include comparison (
gt,lt,gte,lte), equality (eq,ne), string matching (contains,startsWith,endsWith), list membership (in), and logical disjunction (or). - Query parsing happens in
src/parse-where.ts, which splits field operators and handles array conversion for theinoperator. - Record matching is performed by
src/matches-where.ts, which recursively evaluates nested objects and applies short-circuit logic fororconditions. - When present,
_whereoverrides other query parameters like sorting and pagination.
Frequently Asked Questions
How do I filter for values within a specific range using _where?
Combine the gte (greater than or equal) and lte (less than or equal) operators in a single query object. For example, to find posts with views between 100 and 500, use ?_where={"views":{"gte":100,"lte":500}}. JSON Server evaluates both conditions as an implicit AND operation, returning only records that satisfy the range.
Can I use _where to search nested JSON objects?
Yes, the matcher in src/matches-where.ts recursively traverses nested objects. Use dot-path notation or nested JSON structures to target deep fields. For example, ?_where={"author":{"profile":{"age":{"gt":25}}}} filters posts where author.profile.age exceeds 25. The parser handles the nested structure, and the matcher evaluates each level sequentially.
What happens if I combine _where with other query parameters like _sort or _page?
According to the JSON Server source code and README, when _where is present in the query string, it takes precedence and overrides standard filtering, sorting, and pagination parameters. The server processes the complex filter first, then applies any remaining parameters only if they do not conflict with the _where constraints. For predictable results, place all filter logic within the _where JSON object rather than mixing syntaxes.
Why does my _where query return an empty array when I expect results?
This typically occurs due to type mismatches or incorrect operator syntax. The parser in src/parse-where.ts coerces values based on context, but comparing strings to numbers or using unsupported operators causes silent failures. Verify that your JSON is valid, operators are spelled correctly (gt not greaterThan), and field names match your database schema exactly. Check the server logs for parsing errors that indicate which part of the _where object failed validation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →