In This Article

Back to blog

JMESPath in Python: A Practical Guide to Querying JSON

Tutorials

Streamline your Python data processing by mastering JMESPath. We’ll cover installation, syntax fundamentals, advanced filtering, and more.

Vilius Dumcius

Last updated - ‐ 6 min read

Key Takeaways

  • JMESPath is designed to navigate, filter, and extract data from JSON documents using concise expressions.

  • The JMESPath Python library applies expressions directly to Python dictionary structures, streamlining the process of parsing JSON.

  • For Python developers managing deeply nested JSON, JMESPath offers a clear, specified syntax that reduces the need for custom, error-prone logic.

When parsing JSON responses that are deeply nested, Python developers often struggle with verbose loops and error-prone conditional logic. JMESPath provides a declarative query language solution, which enables developers to extract, filter, and transform specific data points from complex structures using concise and readable expressions.

What Is JMESPath?

JMESPath is a specialized JSON query language designed to navigate and select parts of a document. It eliminates the need for extensive custom logic when parsing JSON data.

Similar to using SQL for a database, JMESPath acts as a strong JSON query language for nested structures. The language supports access to nested fields, list slicing, filtering, and the transformation of JSON object data.

It addresses common challenges associated with extracting specific data points from large and complex JSON documents.

Why Use JMESPath in Python?

While developers encounter many standard data formats like CSV or XML, working with APIs returning nested JSON is distinct. Manual loops and conditional statements for parsing JSON and navigating nested structures can be tedious and prone to error.

JMESPath in Python allows for the creation of single expressions to capture desired data. It simplifies data extraction from deeply nested structures, improves code readability, and reduces boilerplate.

For those already using Python for data processing, the tool adds a powerful abstraction layer. Additionally, since JMESPath is a standardized query language, expressions remain reusable across multiple documents and contexts.

Ready to get started?
Register now

Installing and Importing JMESPath

To begin using JMESPath in Python, install the library via pip.

pip install jmespath

It installs the official JMESPath Python package from PyPI. Once installed, import it into your Python script:

import jmespath

data = {
    "foo": {"bar": "baz"},
    "items": [{"name": "Alice"}, {"name": "Bob"}]
}

result = jmespath.search("foo.bar", data)
print(result)

The snippet demonstrates the fundamental import and usage pattern for the library. Running the code should output “baz”.

Note: Ensure your JSON is already parsed into a Python dictionary (using json.loads() or response.json()) before passing it to jmespath.search(). The library operates on Python objects, not raw JSON strings.

Writing Basic Queries in JMESPath

In the JMESPath language, you build a specific string known as a JMESPath expression. A basic query often consists of a simple identifier to select a key from a JSON object. An example of a JMESPath expression would be person.name.

This expression would be used to query JSON data like:

{
  "person": {
    "name": "Jane",
    "age": 30
  }
}

A JMESPath expression like the aforementioned person.name returns “Jane”. For a simpler object like {"foo": "bar"}, the expression foo would simply return "bar". Identifiers represent the most fundamental unit of JMESPath syntax.

You can also access nested keys, such as person.age. For arrays within JSON, you use 0-based index access like items[0], or use wildcards and projections, such as items[*].name, to retrieve all names from a list.

These basic expressions provide efficient access to JSON or nested objects.

Practical Examples of Filtering JSON

The following examples illustrate standard use cases for extracting data using JMESPath.

Extract All Names From a List

Here, we use a list projection to retrieve a specific field from every item in an array:

import jmespath

data = {
    "people": [
        {"name": "Alice", "age": 28},
        {"name": "Bob", "age": 35},
        {"name": "Charlie", "age": 22}
    ]
}

names = jmespath.search("people[*].name", data)
print(names)

Filter by Condition

You can also filter lists based on specific values:

import jmespath

data = {
    "people": [
        {"name": "Alice", "age": 28},
        {"name": "Bob", "age": 35},
        {"name": "Charlie", "age": 22}
    ]
}

adults = jmespath.search("people[?age > `30`].name", data)
print(adults)

# Incorrect: returns None or empty list
incorrect = jmespath.search("people[?name == Alice]", data)
print(incorrect)

# Correct: Uses backticks for the string literal
other_correct = jmespath.search("people[?name == `Alice`]", data)
print(other_correct)

The syntax [?age > 30] filters the list based on a number. When filtering by a specific string (like "Alice"), you must use backticks (`) rather than single quotes. As shown in the example above, [?name == 'Alice'] will fail, while [?name == `Alice`] correctly retrieves the object.

Access Nested Objects

Here we demonstrate drilling down into multiple levels of lists:

import jmespath


data = {
    "departments": [
        {
            "name": "Engineering",
            "employees": [
                {"name": "Alice", "role": "engineer"},
                {"name": "Bob", "role": "senior engineer"}
            ]
        },
        {
            "name": "HR",
            "employees": [
                {"name": "Carol", "role": "recruiter"}
            ]
        }
    ]
}

roles = jmespath.search("departments[].employees[].role", data)
print(roles)

Using the flatten operator [ ] explicitly merges the nested lists into a single, flat array. If you used the list projection [*] here instead, you would end up with a nested list.

JMESPath vs JSONPath: What’s the Difference?

Both JSONPath and JMESPath facilitate data selection from JSON-like structures, yet they possess different syntaxes and capabilities:

Feature JSONPath JMESPath
Syntax style XPath/CSS style ($.store.book[*].author) Independent syntax (books[*].author)
Specification Varies by implementation/library Complete, canonical specification
Focus Selection and pathing Projections and transformations

Note: Unlike JSONPath, JMESPath doesn’t use a root symbol (like $). The expression starts directly with the key name of the data structure you’re passing.

JMESPath provides a complete specification, which ensures consistent behavior across different programming languages. JSONPath libraries occasionally differ in implementation.

For Python developers, the JMESPath library offers straightforward installation and reliable results. JMESPath is the recommended choice for Python environments unless a specific ecosystem requires JSONPath.

Integrating JMESPath With Python Libraries

JMESPath integrates effectively with other standard Python libraries.

With Requests + JSON

You can combine JMESPath with the Requests library to query API responses directly:

import requests
import jmespath

response = requests.get("https://jsonplaceholder.typicode.com/users")
data = response.json()

names = jmespath.search("[*].name", data)
print("Names:", names)

emails = jmespath.search("[?address.city == 'Gwenborough'].email", data)
print("Emails from Gwenborough:", emails)

companies = jmespath.search("[*].company.name", data)
print("Companies:", companies)

The pattern involves fetching a JSON document, parsing it into a Python dictionary , and applying JMESPath for extraction.

With boto3 (AWS SDK for Python)

When using boto3 to interact with AWS services, responses often arrive as deeply nested JSON. You can apply JMESPath expressions to these response dictionaries to isolate relevant resources. The AWS CLI even relies on JMESPath for its --query parameter, which makes the syntax familiar to cloud engineers.

import boto3

client = boto3.client('ec2')
response = client.describe_instances()

instance_ids = jmespath.search("Reservations[].Instances[].InstanceId", response)
print(instance_ids)

With Other Python Packages

Since the library operates on native Python structures, it works with any package producing JSON-like output, including logging frameworks and analytics tools. Such compatibility eliminates the need for custom iterative logic when parsing JSON.

Conclusion

Using JMESPath in Python provides a strong mechanism to query and extract values from JSON data. It functions effectively as a SQL equivalent for JSON documents and nested objects. It removes the need for verbose loops and key checks.

By writing concise JMESPath expressions, you allow the library to handle the complex traversal logic. Integration with libraries like Requests, JSON, and boto3 facilitates handling real-world data efficiently.

Create Account
Share on
Article by IPRoyal
Meet our writers
Data News in Your Inbox

No spam whatsoever, just pure data gathering news, trending topics and useful links. Unsubscribe anytime.

No spam. Unsubscribe anytime.

Related articles