Tutorial · 6 min read

How to Use JSONPath Wildcards and Filters with Examples

Index-based paths break when array lengths change. Wildcards, filters, and recursive descent give you queries that adapt. Use a JSONPath wildcard tester to experiment with every expression in this guide.

1. Wildcard (*): Select Without Knowing Indices

The wildcard * selects all elements at the current level — whether it's an array or an object. This is the foundation of flexible JSONPath queries:

// Sample JSON
{
  "employees": [
    { "name": "Alice", "dept": "Engineering" },
    { "name": "Bob",   "dept": "Design" },
    { "name": "Carol", "dept": "Engineering" }
  ],
  "office": { "city": "New York", "floors": 10 }
}

// Query: all employees
$.employees[*]
// Result: [Alice, Bob, Carol]

// Query: all values in the root object
$.employees, $.office

// Query: all values in office
$.office.*
// Result: ["New York", 10]

Use [*] for arrays and .* for objects. Many implementations treat them the same, but distinguishing them makes intent clearer. If you need a refresher on basic JSONPath syntax, check the JSONPath basic tutorial first.

The JSONPath wildcard tester lets you paste any JSON and test $.* or $[*] instantly.

2. Recursive Descent (..): Find Fields at Any Depth

The double-dot .. operator searches the entire JSON tree, no matter how deeply a field is nested:

// Sample deeply nested JSON
{
  "deep": {
    "deeper": {
      "target": "found me!",
      "array": [
        { "target": "also found" }
      ]
    },
    "sibling": { "target": "and me!" }
  }
}

// Query: find ALL "target" values at any depth
$..target
// Result: ["found me!", "also found", "and me!"]

// Query: find all "target" inside 'deeper' subtree
$.deep.deeper..target
// Result: ["found me!", "also found"]

Performance note: .. visits every node in the JSON tree. On large files, this can be slow. Use it sparingly and prefer targeted paths when you know the structure.

You can combine recursive descent with other operators: $..[?(@.type === 'error')] finds all objects with a type of "error" anywhere in the document.

3. Filter Expressions [?()]: Select by Condition

Filters are the most powerful JSONPath feature. They let you select array elements based on conditions using @ (current element):

// Products data
{
  "products": [
    { "name": "Widget A", "price": 25, "stock": 100 },
    { "name": "Widget B", "price": 50, "stock": 0 },
    { "name": "Widget C", "price": 75, "stock": 10 }
  ]
}

// Filter: find products with price > 30
$.products[?(@.price > 30)]
// Result: [Widget B, Widget C]

// Filter: find products in stock
$.products[?(@.stock > 0)]
// Result: [Widget A, Widget C]

// Filter: exact string match
$.products[?(@.name == "Widget A")]
// Result: [Widget A]

// Filter: using .length on strings
$.products[?(@.name.length > 7)]
// Result: [Widget B, Widget C]

Comparison operators work with numbers, strings, and booleans. Use == for equality, != for not-equal, and <, <=, >, >= for numeric comparison.

4. Multi-Condition Filters with AND/OR

Combine conditions with && (AND) and || (OR). Parentheses control evaluation order:

// More products
{
  "products": [
    { "name": "A", "price": 25,  "stock": 100, "category": "tool" },
    { "name": "B", "price": 50,  "stock": 0,   "category": "tool" },
    { "name": "C", "price": 75,  "stock": 10,  "category": "food" },
    { "name": "D", "price": 100, "stock": 5,   "category": "food" }
  ]
}

// AND: in stock AND category is "tool"
$.products[?(@.stock > 0 && @.category == "tool")]
// Result: [A]

// OR: price > 60 OR out of stock
$.products[?(@.price > 60 || @.stock == 0)]
// Result: [B, C, D]

// Grouped: (in stock AND cheap) OR category tool
$.products[?((@.stock > 0 && @.price < 30) || @.category == "tool")]
// Result: [A, B]

Most JSONPath implementations support these logical operators, but always test complex expressions in a JSONPath tester to confirm behavior matches your expectations.

5. Filtering on Nested Object Properties

You can filter based on nested properties by chaining dot notation inside the filter:

// Users with nested address
{
  "users": [
    {
      "name": "Alice",
      "address": { "city": "New York", "zip": "10001" },
      "scores": [85, 92, 78]
    },
    {
      "name": "Bob",
      "address": { "city": "Boston", "zip": "02101" },
      "scores": [70, 65, 80]
    }
  ]
}

// Filter: users in New York
$.users[?(@.address.city == "New York")]
// Result: [Alice]

// Filter: users with any score >= 90
$.users[?(@.scores[0] >= 90 || @.scores[1] >= 90 || @.scores[2] >= 90)]
// Result: [Alice]

// Filter: users with length of scores > 2
$.users[?(@.scores.length > 2)]
// Result: [Alice, Bob]

Nested dot notation works inside filter expressions the same way it works in paths. You can access array elements by index (@.scores[0]) and object properties by key (@.address.city).

6. Combining Wildcard with Filters

Wildcards and filters work together. The wildcard selects all elements, and the filter narrows them down:

// Mixed structure
{
  "data": {
    "users": [
      { "type": "premium", "name": "Alice" },
      { "type": "free",    "name": "Bob" }
    ],
    "admins": [
      { "type": "premium", "name": "Carol" }
    ]
  }
}

// Find premium users anywhere under data
$.data.*[?(@.type == "premium")]
// Result: [Alice, Carol]

This pattern is especially useful when your JSON has multiple arrays that share the same structure — one wildcard query covers all of them.

Try the JSONPath Tester

Paste any JSON and test wildcards, filters, and recursive descent expressions in real-time. See matched results instantly.

Test JSONPath Now →

Best Practices for JSONPath Wildcards and Filters

Frequently Asked Questions

What is the difference between [*] and .* in JSONPath?

[*] selects all elements of an array, while .* (or ['*']) selects all values of an object. In practice, many implementations treat them interchangeably. Use [*] for arrays and .* for objects for clarity.

Does JSONPath filter support regular expressions?

JSONPath itself does not define regex support, but some implementations (like Goessner's) add it via the ~= operator (e.g., $..[?(@.name ~= /^A.*/)]). Java's Jayway implementation supports the match() function. Check your library's documentation.

Does recursive descent (..) impact performance on large JSON?

Yes. Recursive descent traverses every node in the entire JSON tree. On large files (10,000+ nodes), .. expressions can be significantly slower than explicit paths. Use .. sparingly and prefer targeted paths when performance matters.

Can I use AND/OR in a single JSONPath filter expression?

Yes. Most implementations support logical operators within filter expressions: && for AND, || for OR. Example: $[?(@.price > 10 && @.stock > 0)]. You can also nest filters with parentheses for complex conditions.

Can I export JSONPath query results to CSV?

Some JSONPath testers include a CSV export feature. If not, copy the results and paste them into a JSON to CSV converter, or use a JSONPath library in your programming language to process results programmatically.

Looking for more guides? See the full JSONXX How To index.