Filters allow you to select specific items from arrays based on conditions. Using the ?() operator, you can query data, perform conditional selection, and extract exactly what you need.
Filters are a standard JSONPath feature that enables SQL-like querying of JSON data structures.
Filter Syntax
Filters use the ?() operator with conditional expressions:
? - Indicates a filter operation
(expression) - The condition to evaluate
@ - References the current item being filtered
Basic Filter
With Data
Result
{
"activeUsers" : "$.users[?(@.active===true)]"
}
Filters always return an array , even if only one item matches. To get a single item, you can combine with array indexing: $.users[?(@.active===true)][0]
The @ Symbol
Inside filter expressions, @ represents the current item being evaluated.
Basic @ Usage
Nested Properties
Property Existence
{
"expensiveItems" : "$.products[?(@.price>100)]"
}
{
"products" : [
{ "name" : "Widget" , "price" : 29.99 },
{ "name" : "Gadget" , "price" : 149.99 },
{ "name" : "Doohickey" , "price" : 199.99 }
]
}
{
"expensiveItems" : [
{ "name" : "Gadget" , "price" : 149.99 },
{ "name" : "Doohickey" , "price" : 199.99 }
]
}
@ refers to each product object as it’s evaluated.{
"bostonUsers" : "$.users[?(@.address.city===Boston)]"
}
{
"users" : [
{ "name" : "Alice" , "address" : { "city" : "Boston" }},
{ "name" : "Bob" , "address" : { "city" : "New York" }},
{ "name" : "Charlie" , "address" : { "city" : "Boston" }}
]
}
{
"bostonUsers" : [
{ "name" : "Alice" , "address" : { "city" : "Boston" }},
{ "name" : "Charlie" , "address" : { "city" : "Boston" }}
]
}
Use @.property.nested to access nested values. {
"withISBN" : "$.books[?(@.isbn)]"
}
{
"books" : [
{ "title" : "Book A" , "isbn" : "123" },
{ "title" : "Book B" },
{ "title" : "Book C" , "isbn" : "456" }
]
}
{
"withISBN" : [
{ "title" : "Book A" , "isbn" : "123" },
{ "title" : "Book C" , "isbn" : "456" }
]
}
?(@.isbn) checks if the property exists and is truthy.
Comparison Operators
Use JavaScript comparison operators in filter expressions:
Equality
Numeric Comparisons
String Comparisons
{
"admins" : "$.users[?(@.role===admin)]" ,
"notAdmins" : "$.users[?(@.role!==admin)]" ,
"active" : "$.users[?(@.active===true)]" ,
"inactive" : "$.users[?(@.active===false)]"
}
Operators:
=== - Strict equality (recommended)
!== - Strict inequality
== - Loose equality
!= - Loose inequality
{
"expensive" : "$.products[?(@.price>100)]" ,
"affordable" : "$.products[?(@.price<=50)]" ,
"inRange" : "$.products[?(@.price>=20 && @.price<=100)]"
}
Operators:
> - Greater than
< - Less than
>= - Greater than or equal
<= - Less than or equal
{
"startsWithA" : "$.users[?(@.name[0]===A)]" ,
"longNames" : "$.users[?(@.name.length>10)]" ,
"hasEmail" : "$.users[?(@.email)]"
}
You can access string properties like length and array index [0].
Comparison Operators Reference
Operator Description Example ===Strict equal ?(@.status===active)!==Strict not equal ?(@.status!==deleted)==Loose equal ?(@.count==5)!=Loose not equal ?(@.count!=0)>Greater than ?(@.price>100)<Less than ?(@.age<18)>=Greater or equal ?(@.score>=80)<=Less or equal ?(@.quantity<=10)
Use === (strict equality) instead of == to avoid type coercion issues. For example, 5 == "5" is true, but 5 === "5" is false.
Logical Operators
Combine multiple conditions with logical operators:
AND (&&)
OR (||)
Complex Logic
{
"premiumActive" : "$.users[?(@.tier===premium && @.active===true)]"
}
{
"users" : [
{ "name" : "Alice" , "tier" : "premium" , "active" : true },
{ "name" : "Bob" , "tier" : "premium" , "active" : false },
{ "name" : "Charlie" , "tier" : "basic" , "active" : true }
]
}
{
"premiumActive" : [
{ "name" : "Alice" , "tier" : "premium" , "active" : true }
]
}
Both conditions must be true. {
"highPriority" : "$.tasks[?(@.priority===urgent || @.priority===high)]"
}
{
"tasks" : [
{ "title" : "Task A" , "priority" : "urgent" },
{ "title" : "Task B" , "priority" : "low" },
{ "title" : "Task C" , "priority" : "high" }
]
}
{
"highPriority" : [
{ "title" : "Task A" , "priority" : "urgent" },
{ "title" : "Task C" , "priority" : "high" }
]
}
Either condition can be true. {
"qualified" : "$.candidates[?(@.experience>5 && (@.degree===Masters || @.degree===PhD))]"
}
{
"candidates" : [
{ "name" : "Alice" , "experience" : 7 , "degree" : "Masters" },
{ "name" : "Bob" , "experience" : 3 , "degree" : "PhD" },
{ "name" : "Charlie" , "experience" : 10 , "degree" : "Bachelors" }
]
}
{
"qualified" : [
{ "name" : "Alice" , "experience" : 7 , "degree" : "Masters" }
]
}
Combine multiple AND/OR conditions with parentheses.
Advanced Filter Variables
JSONPath Plus provides special variables for accessing related data:
@root
@parent
@property
@path
Access the root document from within a filter: {
"trigger" : {
"customer_id" : "CUST-123"
},
"orders" : [
{ "id" : "ORD-1" , "customerId" : "CUST-123" },
{ "id" : "ORD-2" , "customerId" : "CUST-456" },
{ "id" : "ORD-3" , "customerId" : "CUST-123" }
]
}
{
"matchingOrders" : [
{ "id" : "ORD-1" , "customerId" : "CUST-123" },
{ "id" : "ORD-3" , "customerId" : "CUST-123" }
]
}
@root lets you compare array items against trigger data or other nodes.Access the parent object of the current item: {
"premiumProducts" : "$.categories..products[?(@parent.tier===premium)]"
}
{
"categories" : [
{
"name" : "Electronics" ,
"tier" : "premium" ,
"products" : [{ "name" : "Laptop" }, { "name" : "Phone" }]
},
{
"name" : "Accessories" ,
"tier" : "basic" ,
"products" : [{ "name" : "Cable" }, { "name" : "Case" }]
}
]
}
{
"premiumProducts" : [
{ "name" : "Laptop" },
{ "name" : "Phone" }
]
}
Access the property name or array index of the current item: {
"notFirst" : "$.items[?(@property!==0)]"
}
{
"items" : [ "Apple" , "Banana" , "Cherry" ]
}
{
"notFirst" : [ "Banana" , "Cherry" ]
}
@property is the index (0, 1, 2) for array items.Access the JSONPath string to the current item: {
"notFirstBook" : "$.store.book[?(@path!== \" $['store']['book'][0] \" )]"
}
Useful for excluding specific paths or comparing locations.
Filter Variables Reference
Variable Description Example @Current item ?(@.price>10)@.propertyItem’s property ?(@.active===true)@rootRoot document ?(@[email protected] )@parentParent object ?(@parent.category===premium)@propertyProperty name/index ?(@property!==0)@parentPropertyParent’s property name ?(@parentProperty!==hidden)@pathJSONPath to item ?(@path!==\"$[0]\")
Type Selectors in Filters
Filter by data type using type selector operators:
Primitive Types
Complex Types
Numeric Types
{
"stringValues" : "$.data[*][?(@string())]" ,
"numberValues" : "$.data[*][?(@number())]" ,
"booleanValues" : "$.data[*][?(@boolean())]"
}
{
"data" : [
{ "value" : "text" },
{ "value" : 42 },
{ "value" : true },
{ "value" : "another string" }
]
}
Select items by their type. {
"arrays" : "$.data[*][?(@array())]" ,
"objects" : "$.data[*][?(@object())]" ,
"nullValues" : "$.data[*][?(@null())]"
}
{
"data" : [
{ "value" : [ 1 , 2 , 3 ]},
{ "value" : { "nested" : true }},
{ "value" : null },
{ "value" : "text" }
]
}
{
"integers" : "$.data[*][?(@integer())]" ,
"allNumbers" : "$.data[*][?(@number())]"
}
{
"data" : [
{ "value" : 42 },
{ "value" : 3.14 },
{ "value" : 100 },
{ "value" : "text" }
]
}
{
"integers" : [{ "value" : 42 }, { "value" : 100 }],
"allNumbers" : [{ "value" : 42 }, { "value" : 3.14 }, { "value" : 100 }]
}
Type Selectors Reference
Selector Matches Example @string()String values ?(@string())@number()All numbers ?(@number())@integer()Integer numbers only ?(@integer())@boolean()true or false ?(@boolean())@array()Arrays ?(@array())@object()Objects ?(@object())@null()null values ?(@null())@scalar()Non-object/non-function ?(@scalar())
Complex Filter Patterns
Range Filtering
Multiple Conditions
Exclusion Filtering
Nested Array Filtering
Cross-Reference
{
"midRange" : "$.products[?(@.price>=50 && @.price<=150)]"
}
Select items within a numeric range. {
"qualified" : "$.users[?(@.active===true && @.verified===true && @.score>=80)]"
}
Require multiple conditions to all be true. {
"notDeleted" : "$.items[?(@.status!==deleted && @.status!==archived)]"
}
Exclude items with specific values. {
"hasHighPriorityTask" : "$.users[?(@.tasks[?(@.priority===high)])]"
}
Filter based on nested array contents (users who have high-priority tasks). Filter array items against trigger data or other node values.
Real-World Examples
E-commerce Orders
User Management
Inventory Management
Task Management
{
"recentOrders" : "$.orders[?(@.total>100 && @.status===completed)]" ,
"pendingHighValue" : "$.orders[?(@.status===pending && @.total>500)]" ,
"freeShipping" : "$.orders[?(@.total>=50)]" ,
"needsReview" : "$.orders[?(@.total>1000 && @.verified===false)]"
}
Common e-commerce filtering patterns. {
"activeAdmins" : "$.users[?(@.role===admin && @.active===true)]" ,
"suspendedUsers" : "$.users[?(@.status===suspended)]" ,
"newUsers" : "$.users[?(@.createdDays<30)]" ,
"premiumExpiring" : "$.users[?(@.tier===premium && @.daysUntilExpiry<7)]"
}
{
"lowStock" : "$.products[?(@.quantity<10)]" ,
"outOfStock" : "$.products[?(@.quantity===0)]" ,
"needsReorder" : "$.products[?(@.quantity<@.reorderPoint)]" ,
"highValue" : "$.products[?(@.quantity*@.price>10000)]"
}
Inventory alerts and monitoring. {
"urgent" : "$.tasks[?(@.priority===urgent && @.status!==completed)]" ,
"overdue" : "$.tasks[?(@.dueDate<@root.trigger.currentDate && @.status!==completed)]" ,
"myTasks" : "$.tasks[?(@[email protected] _id)]" ,
"blockedTasks" : "$.tasks[?(@.blockedBy)]"
}
Combining Filters with Other Operations
Filter + Array Index
Filter + Property Access
Filter + Pipe Operator
Multiple Filters
{
"firstActive" : "$.users[?(@.active===true)][0]" ,
"lastPremium" : "$.users[?(@.tier===premium)][-1]"
}
Get a single item from filtered results. {
"activeUserNames" : "$.users[?(@.active===true)].name" ,
"premiumEmails" : "$.users[?(@.tier===premium)].email"
}
Extract specific properties from filtered items. {
"activeList" : "Active users: |$.users[?(@.active===true)].name|" ,
"count" : "Found |$.products[?(@.price>100)].length| expensive items"
}
Use filtered results in string concatenation. {
"specific" : "$.categories[?(@.name===Electronics)].products[?(@.price<100)]"
}
Chain filters to narrow down results progressively.
Common Pitfalls
Wrong: "$.users[?(@.role=admin)]" // ❌ Single = is assignment, not comparison
Correct: "$.users[?(@.role===admin)]" // ✅ Use === for comparison
Forgetting Quotes for Strings
Wrong: "$.users[?(@.status===active)]" // ❌ Missing quotes around 'active'
Correct: "$.users[?(@.status==='active')]" // ✅ Strings need quotes
Note: In some implementations, quotes are optional, but it’s best practice to include them.
Issue: { "user" : "$.users[?(@.id===123)]" } // Returns array, not single object
Solution: { "user" : "$.users[?(@.id===123)][0]" } // Add [0] to get first item
Issue: "$.users[?(@.middleName===Smith)]" // What if middleName doesn't exist?
Better: "$.users[?(@.middleName && @.middleName===Smith)]" // Check existence first
Efficient Filters // ✅ Simple conditions
"$.users[?(@.active===true)]"
// ✅ Direct property checks
"$.items[?(@.price>100)]"
Slower Filters // ⚠️ Complex nested filters
"$.data[?(@.nested[?(@.x>5)])]"
// ⚠️ Many conditions
"$.items[?(@.a && @.b && @.c && @.d)]"
Optimization tips:
Filter early in your JSONPath expression to reduce data being processed
Use simple conditions when possible
Consider splitting complex filters into multiple steps
Test with realistic data sizes
Building Complex Filters
Start Simple
Begin with a basic filter: { "filtered" : "$.items[?(@.price>10)]" }
Add One Condition
Add conditions incrementally: { "filtered" : "$.items[?(@.price>10 && @.active===true)]" }
Test Each Addition
Verify the filter works after each change using the Flow Debugger
Use Parentheses for Complex Logic
Group conditions clearly: { "filtered" : "$.items[?(@.price>10 && (@.category===A || @.category===B))]" }
Consider Readability
If the filter becomes too complex, consider:
Breaking into multiple filters
Using separate nodes for each filter step
Adding comments in your flow documentation
Quick Reference
Always returns an array
Use @ for current item
Combine with [0] for single item
Prefer === over == for type safety
Use parentheses for complex logic
@ Current item
@root Root document
@parent Parent object
@property Property name/index
@path JSONPath to item
What’s Next?