Conditional JSONPath: turn an API response into answers
An order list is easy to read until you need only paid orders over a threshold, or records missing a field. A JSONPath filter lets you ask that question directly.
By JSON Path Viewer · Published · 6 min read
How do you write a conditional JSONPath? Add [?(<condition>)] to an array path. For example, $.orders[?(@.total >= 100)] selects orders whose total is at least 100. The @ refers to the current item. Combine conditions with && (AND) or || (OR).
One response, several useful questions
This fictional orders response deliberately includes an empty coupon string, explicit nulls, and an omitted coupon. Those differences matter when checking an API contract. Every “Run this example” link loads this same fixture and evaluates the query in the tester.
{
"orders": [
{ "id": "A100", "status": "paid", "total": 120,
"customer": { "region": "US" }, "coupon": null },
{ "id": "A101", "status": "pending", "total": 85,
"customer": { "region": "EU" }, "coupon": "WELCOME" },
{ "id": "A102", "status": "paid", "total": 45,
"customer": { "region": "US" }, "coupon": "" },
{ "id": "A103", "status": "paid", "total": 210,
"customer": { "region": "EU" } },
{ "id": "A104", "status": "cancelled", "total": 20,
"customer": { "region": "US" }, "coupon": null }
]
}
1. Select by one condition
$.orders[?(@.status == "paid")].id
Result: ["A100", "A102", "A103"]. The filter selects matching order objects; the final .id extracts their IDs. Remove that suffix when you need the complete orders for inspection.
Combine conditions with AND and OR
2. Paid orders worth at least 100
$.orders[?(@.status == "paid" && @.total >= 100)].id
Result: ["A100", "A103"]. AND requires both comparisons to pass for the same order. A102 is paid, but its total of 45 excludes it. Keep 100 unquoted because the fixture stores totals as numbers.
3. Orders that are pending or cancelled
$.orders[?(@.status == "pending" || @.status == "cancelled")].id
Result: ["A101", "A104"]. OR keeps an item if either condition passes. Repeat the field in each comparison: @.status == "pending" || "cancelled" is not an equivalent test. When mixing AND and OR, add parentheses around the alternatives so your intent is clear.
Filter a nested field, then return a different field
4. Paid orders from the EU region
$.orders[?(@.status == "paid" && @.customer.region == "EU")].id
Result: ["A103"]. Both EU orders have a customer region, but A101 is pending. Notice that the condition reads a nested value while the suffix returns the order ID.
Every sample order has a customer object. If your API can omit it, use the visual builder for nested fields; it adds checks for missing or null parents before accessing the child. For a literal key named customer.region, enter ["customer.region"] instead of a dotted path.
Null, missing, and empty are different cases
A null coupon can mean the API explicitly recorded “no coupon.” A missing property can mean the producer did not send that field. An empty string is still a present string value. Combining these cases can hide a data-quality problem.
5. Explicitly null coupons
$.orders[?(@.coupon === null)].id
Result: ["A100", "A104"]. This JSONPath Plus expression uses strict equality to keep null separate from a missing field.
6. Orders missing the coupon field
$.orders[?(@.coupon === undefined)].id
Result: ["A103"]. Here undefined is an expression value in the JSONPath Plus evaluator; it is not valid JSON data. A102 has an empty string, so it does not match either this query or the null query.
Check the JSONPath dialect. These examples run on JSONPath Plus. Its strict equality, undefined, and JavaScript-style type checks are extensions, not portable RFC 9535 syntax. An RFC 9535 implementation uses a query such as $.orders[?(!@.coupon)] to check for an absent coupon. Do not assume that expression has the same existence semantics in every engine.
Build conditions without memorizing the syntax
Start from the value you want. Select an order ID in the tree and choose Find group. Choose status under Where and "paid" under Is, then select Run to return the IDs of all paid orders. The choices come from actual values in your JSON. If the selected value sits inside several arrays, choose a Parent collection to filter at the level you need. For example, selecting a member's email and grouping its parent teams by region returns emails from all members of those teams. Choose Advanced to add more conditions to a group filter.
To write a condition yourself:
- Open a runnable example above, then select Filter in Output.
- Set From array to
$.orders. Enterstatus, choose “equals,” and typepaid. - Add a second condition for
total, choose “is at least,” and enter100. Select All (AND). - Set Return field to
idand choose Run. The result should contain A100 and A103.
After a successful run, the controls collapse to leave room for the results. A sentence describes what the filter returns; choose Edit filter to change it. Choose Show flow to see the source collection, matching items, and final values in a diagram. The same explanation is available when you choose a group from the tree.
Use Share in the Output header to create a link to your session. The adjacent Output actions menu (⋯) contains Clear query, Expand tree, Collapse tree, and Settings.
The builder detects value types automatically: 100 is a number, true is a boolean, and paid is text. Add double quotes to keep numeric text as a string, such as "100". Equality uses a simple strict comparison; the builder adds checks for missing or null parents only when needed for your data. “Exists” includes null, false, zero, and empty strings; “Is missing” checks absence. Ordering comparisons require a number. You can combine up to eight conditions or edit the generated JSONPath directly for more complex grouping.
When a filter returns the wrong result
- Check the array path first. Run
$.ordersto confirm that it selects the collection you intended. - Inspect types in the tree. A quoted amount is a string. The builder intentionally avoids converting it to a number.
- Test conditions separately. If a combined filter returns nothing, run each comparison alone to find the one excluding your record.
- Separate zero matches from invalid syntax. A valid query may have no matches. An incomplete expression or unsupported operator needs correcting before its result is meaningful.
- Verify in the destination engine. A query that works in this tester may need adjustment for a monitoring tool or a library using a different dialect.
For roots, wildcards, array indexes, and slices, continue with the JSONPath syntax reference. Parsing and evaluation happen in your browser. Creating a Share link uploads the document and expression so the session can be reopened for 90 days.
References and compatibility
The IETF JSONPath standard, RFC 9535, defines standardized filter semantics. The JSONPath Plus documentation describes the evaluator and extensions used by this tool. The six recipes above are tested against the bundled browser engine and the exact fixture shown here.