JSONPath Query

JSONPath is a query language for JSON, similar to XPath for XML. It allows you to extract and filter data from JSON documents using a concise path expression syntax. JSONPath expressions always start with $ which represents the root of the JSON document.

Basic Concept

In JSONPath, $ represents the root of the JSON document. All JSONPath expressions start from this root reference and navigate through the JSON structure using dot notation, bracket notation, and various operators.

Syntax Overview

Basic Access

// Access root object
$

// Access property
$.propertyName

// Access array element
$.arrayName[0]

// Access nested property
$.user.profile.name

Array Operations

// Get array length (context-dependent)
$.users.length

// Access first element
$.users[0]

// Access last element
$.users[-1]

// Access multiple elements
$.users[0,1]

// Array slice (start:end)
$.users[0:2]

JSONPath Operators

OperatorDescriptionExample
$Root object$
.Child operator$.store.book
[]Subscript operator$.store.book[0]
*Wildcard$.store.*
..Recursive descent$..author
[start:end]Array slice$.store.book[0:2]
[?()]Filter expression$.store.book[?(@.price < 10)]
@Current object in filter@.price

Query Examples

Sample JSON Data

{
  "store": {
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      {
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      {
        "category": "fiction",
        "author": "Herman Melville", 
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  },
  "users": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "[email protected]",
      "age": 30,
      "active": true,
      "address": {
        "street": "123 Main St",
        "city": "New York",
        "zipcode": "10001"
      }
    },
    {
      "id": 2,
      "name": "Jane Smith", 
      "email": "[email protected]",
      "age": 25,
      "active": false,
      "address": {
        "street": "456 Oak Ave",
        "city": "Los Angeles", 
        "zipcode": "90210"
      }
    }
  ]
}

Basic Queries

// Get all books
$.store.book

// Get first book
$.store.book[0]

// Get book title
$.store.book[0].title

// Get bicycle color
$.store.bicycle.color

// Get all users
$.users

Advanced Queries

// Get all authors (recursive search)
$..author

// Get all prices in the store
$.store..price

// Get all titles
$..title

// Get all user names
$.users[*].name

// Get all cities
$.users[*].address.city

Array Operations

Indexing and Slicing

// First book
$.store.book[0]

// Last book
$.store.book[-1]

// First two books
$.store.book[0:2]

// All books from index 1
$.store.book[1:]

// Multiple specific books
$.store.book[0,2]

// All books (wildcard)
$.store.book[*]

Filtering

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

// Books in fiction category
$.store.book[?(@.category == 'fiction')]

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

// Active users
$.users[?(@.active == true)]

// Users older than 25
$.users[?(@.age > 25)]

// Users in specific city
$.users[?(@.address.city == 'New York')]

Filter Expressions

Comparison Operators

// Equal
$.users[?(@.age == 30)]

// Not equal
$.users[?(@.age != 30)]

// Less than
$.store.book[?(@.price < 10)]

// Greater than
$.users[?(@.age > 25)]

// Less than or equal
$.store.book[?(@.price <= 10)]

// Greater than or equal
$.users[?(@.age >= 25)]

Logical Operators

// AND condition
$.users[?(@.age > 25 && @.active == true)]

// OR condition
$.store.book[?(@.category == 'fiction' || @.price < 10)]

// NOT condition
$.users[?(!@.active)]

Pattern Matching

// Regex match (implementation dependent)
$.users[?(@.email =~ /.*@example\.com/)]

// String contains (implementation dependent)
$.store.book[?(@.title =~ /.*Sword.*/)]

// Property existence
$.store.book[?(@.isbn)]

Recursive Descent

// Find all price properties anywhere
$..price

// Find all name properties anywhere
$..name

// Find all properties at any level
$..*

// Find specific property recursively
$..address.city

// Find nested array elements
$..book[*].author

Wildcard Operations

// All properties of store
$.store.*

// All elements in book array
$.store.book[*]

// All properties of first book
$.store.book[0].*

// All user properties
$.users[*]

// All nested properties
$.users[*].*

Common Patterns

Data Extraction

// Get all book titles
$.store.book[*].title

// Get all user emails
$.users[*].email

// Get all addresses
$.users[*].address

// Get all zipcodes
$.users[*].address.zipcode

Data Filtering

// Expensive books
$.store.book[?(@.price > 10)]

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

// Books with ISBN
$.store.book[?(@.isbn)]

// Active users in New York
$.users[?(@.active == true && @.address.city == 'New York')]

Complex Queries

// Books by specific author
$.store.book[?(@.author == 'Herman Melville')]

// Users with specific email domain
$.users[?(@.email =~ /.*@example\.com/)]

// All items with price between 5 and 15
$..[?(@.price >= 5 && @.price <= 15)]

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

JSONPath Functions

Some implementations support functions:

// Array length
$.store.book.length()

// Minimum price
$.store.book[*].price.min()

// Maximum price
$.store.book[*].price.max()

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

// Sum of prices
$.store.book[*].price.sum()

Best Practices

  1. Start with root: Always begin expressions with $
  2. Use filters wisely: Filter expressions can be expensive, use them judiciously
  3. Bracket vs dot notation: Use brackets for property names with spaces or special characters
  4. Test expressions: Validate JSONPath expressions with sample data
  5. Consider performance: Recursive descent (..) can be slow on large documents
  6. Use specific paths: More specific paths are generally faster than wildcards

Error Handling

// Handle missing properties gracefully
$.users[*].profile.avatar  // Returns empty if profile doesn't exist

// Filter for existence before access
$.users[?(@.profile)].profile.avatar

// Use optional access patterns
$.users[*].address.street  // May return fewer results than users

Implementation Notes

Different JSONPath implementations may have variations in:

  • Function support
  • Regex syntax
  • Filter expression capabilities
  • Return value formats
  • Error handling

Always refer to your specific JSONPath library documentation for exact syntax and features.

Comparison with Other Query Languages

FeatureJSONPathXPathCSS Selectors
Root$/N/A
Wildcard***
Recursive..//N/A
Filter[?()][][]
Array slice[start:end]N/AN/A

JSONPath provides a powerful and intuitive way to query JSON documents, making it easy to extract specific data from complex nested structures.