Skip to main content
Blog / JSON Tools

JSONPath Expressions - Query JSON Like a Pro

Master JSONPath expressions to query and extract data from JSON documents efficiently. Learn syntax, operators, and practical examples.

DevToolsCenter Team
9 min read

What is JSONPath?

JSONPath is a query language for JSON, similar to how XPath is used for XML. It provides a simple way to navigate through complex JSON structures and extract specific data without writing complex parsing logic.

Why Use JSONPath?

  • Extract specific data from large JSON responses
  • Test API responses for expected values
  • Transform data by selecting specific fields
  • Navigate complex nested structures easily
  • Query arrays with filtering capabilities

Basic Syntax

JSONPath expressions always start with $ representing the root element.

{
  "store": {
    "book": [
      {
        "title": "JavaScript Guide",
        "price": 29.99
      },
      {
        "title": "Python Basics",
        "price": 34.99
      }
    ]
  }
}

Basic Operators

Operator Description Example
$ Root element $
. Child operator $.store.book
[] Subscript operator $[0]
* Wildcard $.store.*
.. Recursive descent $..price
@ Current element (in filters) $..book[?(@.price < 30)]

Accessing Data

Accessing Objects

Dot notation:

$.store.book
// Returns: entire book array

Bracket notation:

$['store']['book']
// Returns: same as above

Accessing Arrays

By index:

$.store.book[0]
// Returns: first book

Multiple indices:

$.store.book[0,1]
// Returns: first two books

Array slicing:

$.store.book[0:2]  // First two books
$.store.book[-1]   // Last book
$.store.book[1:]   // All books from index 1
$.store.book[:2]   // First two books

Wildcard Selection

All children:

$.store.book[*]
// Returns: all books

$.store.book[*].title
// Returns: all book titles

All properties:

$.*
// Returns: all top-level properties

Recursive Descent

The .. operator searches through all levels:

$..price
// Returns: all price values at any level

$..book[*].author
// Returns: all authors from book arrays at any level

Example with nested data:

{
  "company": {
    "departments": [
      {
        "name": "Engineering",
        "employees": [
          {"name": "John", "salary": 80000},
          {"name": "Jane", "salary": 90000}
        ]
      }
    ]
  }
}
$..salary
// Returns: [80000, 90000]

Filtering

Filters allow you to select elements based on conditions.

Filter Syntax

$..book[?(@.price < 30)]
// Books with price less than 30

$..book[?(@.author == 'John')]
// Books by John

Comparison Operators

Operator Description Example
== Equal ?(@.price == 10)
!= Not equal ?(@.price != 10)
< Less than ?(@.price < 30)
<= Less or equal ?(@.price <= 30)
> Greater than ?(@.price > 30)
>= Greater or equal ?(@.price >= 30)
=~ Regex match ?(@.title =~ /java.*/)

Logical Operators

AND condition:

$..book[?(@.price > 20 && @.price < 40)]
// Books with price between 20 and 40

OR condition:

$..book[?(@.category == 'fiction' || @.category == 'science')]
// Fiction or science books

NOT condition:

$..book[?(!@.isbn)]
// Books without ISBN

Existence Checks

$..book[?(@.isbn)]
// Books that have ISBN field

$..book[?(@.discount)]
// Books with discount

Practical Examples

Example 1: API Response

{
  "users": [
    {
      "id": 1,
      "name": "John",
      "email": "john@example.com",
      "active": true,
      "roles": ["admin", "user"]
    },
    {
      "id": 2,
      "name": "Jane",
      "email": "jane@example.com",
      "active": false,
      "roles": ["user"]
    }
  ]
}

Queries:

// All user names
$.users[*].name
// Result: ["John", "Jane"]

// Active users
$.users[?(@.active == true)]
// Result: [{ id: 1, name: "John", ... }]

// Admins
$.users[?(@.roles[*] == 'admin')]
// Result: [{ id: 1, name: "John", ... }]

// Email of first user
$.users[0].email
// Result: "john@example.com"

Example 2: E-commerce Data

{
  "store": {
    "products": [
      {
        "id": 1,
        "name": "Laptop",
        "price": 999,
        "stock": 5,
        "category": "electronics"
      },
      {
        "id": 2,
        "name": "Mouse",
        "price": 25,
        "stock": 50,
        "category": "electronics"
      },
      {
        "id": 3,
        "name": "Desk",
        "price": 299,
        "stock": 0,
        "category": "furniture"
      }
    ]
  }
}

Queries:

// Products under $100
$.store.products[?(@.price < 100)]

// Out of stock items
$.store.products[?(@.stock == 0)]

// Electronics in stock
$.store.products[?(@.category == 'electronics' && @.stock > 0)]

// All product names
$.store.products[*].name

// Expensive electronics
$.store.products[?(@.category == 'electronics' && @.price > 500)]

Example 3: Nested API Response

{
  "data": {
    "posts": [
      {
        "id": 1,
        "title": "First Post",
        "author": {
          "name": "John",
          "verified": true
        },
        "comments": [
          {"text": "Great!", "likes": 5},
          {"text": "Thanks", "likes": 2}
        ]
      },
      {
        "id": 2,
        "title": "Second Post",
        "author": {
          "name": "Jane",
          "verified": false
        },
        "comments": [
          {"text": "Nice", "likes": 10}
        ]
      }
    ]
  }
}

Queries:

// All post titles
$.data.posts[*].title

// Posts by verified authors
$.data.posts[?(@.author.verified == true)]

// All comments
$..comments[*]

// Comments with more than 3 likes
$..comments[?(@.likes > 3)]

// Names of all authors
$.data.posts[*].author.name

// All likes values
$..likes

Advanced Techniques

Functions

Some JSONPath implementations support functions:

// Length of array
$.store.products.length()

// Min/Max values
$.store.products[*].price.min()
$.store.products[*].price.max()

// Average
$.store.products[*].price.avg()

Script Expressions

// Complex conditions
$.store.products[?(@.price * @.stock > 1000)]

// Mathematical operations
$.store.products[?(@.price > (@.originalPrice * 0.8))]

Multiple Conditions

// Complex filtering
$..products[?(
  @.category == 'electronics' &&
  @.stock > 0 &&
  @.price < 1000 &&
  @.rating >= 4
)]

Common Use Cases

1. API Testing

Validate API responses:

// Check if user is admin
$.user.roles[?(@=='admin')]

// Verify all products have prices
$.products[*].price

// Check for errors
$..error

2. Data Transformation

Extract specific fields:

// Get user IDs and emails only
$.users[*]['id','email']

// Extract nested data
$..orders[*].items[*].name

3. Monitoring & Logging

Query log structures:

// Find error logs
$..logs[?(@.level == 'error')]

// Get timestamps of warnings
$..logs[?(@.level == 'warn')].timestamp

4. Configuration Management

Navigate config files:

// Database settings
$.config.database

// All enabled features
$..features[?(@.enabled == true)].name

JSONPath vs Other Query Languages

JSONPath vs XPath

XPath (XML):

//book[@price < 30]/title

JSONPath (JSON):

$..book[?(@.price < 30)].title

JSONPath vs SQL

SQL:

SELECT name FROM users WHERE age > 18

JSONPath:

$.users[?(@.age > 18)].name

JSONPath vs jq

jq:

.users[] | select(.age > 18) | .name

JSONPath:

$.users[?(@.age > 18)].name

Implementation Libraries

JavaScript

const jsonpath = require('jsonpath');
const result = jsonpath.query(data, '$.users[*].name');

Python

from jsonpath_ng import parse

expression = parse('$.users[*].name')
results = [match.value for match in expression.find(data)]

Java

List<String> names = JsonPath.read(json, "$.users[*].name");

Go

import "github.com/oliveagle/jsonpath"

res, err := jsonpath.JsonPathLookup(data, "$.users[*].name")

Best Practices

  1. Start simple and build up

    • Test basic paths first
    • Add complexity gradually
  2. Use specific paths when possible

    // Specific (faster)
    $.users[0].name
    
    // General (slower)
    $..name
  3. Validate your paths

    • Test with sample data
    • Handle empty results
  4. Consider performance

    • Recursive descent (..) can be slow
    • Filter early in the path
  5. Document complex expressions

    // Get active premium users with recent activity
    $.users[?(
      @.active == true &&
      @.plan == 'premium' &&
      @.lastActivity > '2025-01-01'
    )]

Common Pitfalls

1. Array vs Object Confusion

// Wrong - treating object as array
$.user[0].name

// Correct
$.user.name

2. Incorrect Filter Syntax

// Wrong - missing @ symbol
$..book[?(price < 30)]

// Correct
$..book[?(@.price < 30)]

3. String Comparison

// Wrong - number comparison on string
$..book[?(@.isbn > 1000)]

// Correct - string comparison
$..book[?(@.isbn)]

Conclusion

JSONPath is a powerful tool for querying JSON data. Whether you're testing APIs, transforming data, or navigating complex structures, mastering JSONPath will make you more efficient.

Key takeaways:

  • Start with $ for root
  • Use . for child navigation
  • Use .. for recursive search
  • Use filters [?()] for conditional selection
  • Practice with real-world examples

The more you use JSONPath, the more natural it becomes. Start with simple queries and gradually tackle more complex scenarios as you build confidence.

Try JSONPath Tester Now

Ready to put this into practice? Use our free JSONPath Tester tool. It works entirely in your browser with no signup required.

Launch JSONPath Tester
Free Forever No Signup Browser-Based

Frequently Asked Questions

Q Is JSONPath part of the JSON spec?

A

No. JSONPath is a separate query language; implementations differ slightly between libraries.