JSONPath :contains filter
Categories:
Mastering JSONPath's :contains Filter for Dynamic Data Selection

Explore the powerful JSONPath :contains filter to efficiently query and extract data based on substring matches within JSON documents. Learn its syntax, use cases, and practical applications.
JSONPath is a query language for JSON, similar to XPath for XML. It allows you to select and extract specific elements from a JSON document. While basic JSONPath expressions are great for direct property access or array indexing, real-world data often requires more sophisticated filtering. This is where the :contains
filter comes in handy, enabling you to select elements whose string values contain a specified substring. This article will delve into the :contains
filter, demonstrating its utility with practical examples.
Understanding the :contains Filter Syntax
The :contains
filter is typically used within a bracketed filter expression []
following a path segment. Its primary purpose is to match string values that include a given substring. The general syntax looks like this:
$.path.to.array[?(@.property :contains 'substring')]
Here's a breakdown of the components:
$
: Represents the root of the JSON document.path.to.array
: The path to an array or collection of objects.[?(...)]
: The filter expression, where?
indicates a filter and the parentheses contain the condition.@.property
: Refers to the current element's property being evaluated within the filter.@
represents the current node.:contains 'substring'
: The core of the filter, checking if the value ofproperty
contains the specified'substring'
.
:contains
filter is case-sensitive in most JSONPath implementations. If you need case-insensitive matching, you might need to preprocess your data or use a JSONPath implementation that supports regular expressions.Practical Applications and Examples
Let's illustrate the :contains
filter with a common scenario: searching for items in a product catalog. Consider the following JSON data representing a list of products:
{
"products": [
{
"id": 1,
"name": "Laptop Pro 15-inch",
"category": "Electronics",
"description": "High-performance laptop for professionals."
},
{
"id": 2,
"name": "Wireless Mouse",
"category": "Accessories",
"description": "Ergonomic mouse with long battery life."
},
{
"id": 3,
"name": "Gaming Keyboard RGB",
"category": "Electronics",
"description": "Mechanical keyboard with customizable RGB lighting."
},
{
"id": 4,
"name": "USB-C Hub",
"category": "Accessories",
"description": "Multi-port adapter for modern devices."
}
]
}
Sample JSON data for product catalog
Now, let's use :contains
to find products based on their names or descriptions.
Example 1: Finding Products by Name
Suppose we want to find all products whose names contain the word "Laptop".
$.products[?(@.name :contains 'Laptop')]
JSONPath expression to find products with 'Laptop' in their name
This expression would return the first product:
[
{
"id": 1,
"name": "Laptop Pro 15-inch",
"category": "Electronics",
"description": "High-performance laptop for professionals."
}
]
Example 2: Searching in Descriptions
What if we want to find products with "RGB" in their description?
$.products[?(@.description :contains 'RGB')]
JSONPath expression to find products with 'RGB' in their description
This would yield the third product:
[
{
"id": 3,
"name": "Gaming Keyboard RGB",
"category": "Electronics",
"description": "Mechanical keyboard with customizable RGB lighting."
}
]
Combining Filters
You can combine the :contains
filter with other JSONPath filters or logical operators (if supported by your JSONPath implementation) to create more complex queries. For instance, finding electronics products whose names contain "Mouse".
$.products[?(@.category == 'Electronics' && @.name :contains 'Mouse')]
Combined JSONPath expression for category and name search
Given our sample data, this specific query would return an empty array, as the 'Wireless Mouse' is in the 'Accessories' category, not 'Electronics'. However, if we searched for 'Mouse' in 'Accessories':
$.products[?(@.category == 'Accessories' && @.name :contains 'Mouse')]
This would correctly return the 'Wireless Mouse' product.
flowchart TD A[Start JSONPath Query] B{Select 'products' array} C{Filter products} D{"@.name :contains 'Laptop'"} E[Return Matching Products] A --> B B --> C C -- For each product --> D D -- True --> E D -- False --> C
Flowchart of JSONPath :contains filter logic
:contains
filter or the exact same syntax for it. Always consult the documentation of the specific JSONPath library or tool you are using (e.g., Jayway JSONPath, JSONPath-Plus, etc.). Some might require regular expressions for similar functionality.JSONPath Implementations and Regex Alternatives
While :contains
is a convenient shorthand, some JSONPath libraries offer more powerful regular expression capabilities. For example, in Jayway JSONPath (a popular Java implementation), you can use the =~
operator for regex matching. This provides greater flexibility, including case-insensitive searches or more complex pattern matching.
For instance, to find products with 'laptop' (case-insensitive) in their name using a regex-enabled JSONPath:
$.products[?(@.name =~ /laptop/i)]
This would achieve a similar result to :contains
but with added control over the matching behavior.
JavaScript (JSONPath-Plus)
const JSONPath = require('jsonpath-plus').JSONPath;
const data = { "products": [ { "id": 1, "name": "Laptop Pro 15-inch", "category": "Electronics", "description": "High-performance laptop for professionals." }, { "id": 2, "name": "Wireless Mouse", "category": "Accessories", "description": "Ergonomic mouse with long battery life." }, { "id": 3, "name": "Gaming Keyboard RGB", "category": "Electronics", "description": "Mechanical keyboard with customizable RGB lighting." } ] };
// Using :contains (if supported by the specific JSONPath-Plus version/config) // Note: JSONPath-Plus often relies on regex for advanced filtering. // A direct ':contains' operator is not standard across all implementations. // For substring matching, regex is the more robust approach.
// Example using regex for substring match (equivalent to :contains) const result = JSONPath({ path: "$.products[?(@.name =~ /Laptop/)]", json: data });
console.log(JSON.stringify(result, null, 2));
// For a true ':contains' like behavior, you might implement a custom filter // or rely on regex as shown above.
Python (jsonpath-rw)
from jsonpath_rw import jsonpath, parse import json
data = { "products": [ { "id": 1, "name": "Laptop Pro 15-inch", "category": "Electronics", "description": "High-performance laptop for professionals." }, { "id": 2, "name": "Wireless Mouse", "category": "Accessories", "description": "Ergonomic mouse with long battery life." }, { "id": 3, "name": "Gaming Keyboard RGB", "category": "Electronics", "description": "Mechanical keyboard with customizable RGB lighting." } ] }
jsonpath-rw does not have a direct ':contains' filter.
You would typically use a custom filter or regex for this.
Example using a custom filter function for substring match
This demonstrates the concept, but actual implementation might vary.
For simple substring, Python's 'in' operator is used.
Define a custom filter function
class ContainsFilter(jsonpath.JsonPath): def init(self, field_name, substring): self.field_name = field_name self.substring = substring
def find(self, data):
for datum in data:
if isinstance(datum.value, dict) and self.field_name in datum.value:
field_value = datum.value[self.field_name]
if isinstance(field_value, str) and self.substring in field_value:
yield datum
Apply the custom filter
Note: This is a conceptual example. jsonpath-rw's filter syntax is different.
A more direct way in jsonpath-rw for regex is:
expr = parse('products[*][?name =~ "Laptop"]') # Requires regex support
For simple substring, you might iterate or use a more advanced library.
A common approach is to filter after initial selection if the library lacks direct ':contains'.
Using a more direct approach with regex if available in a different library
from jsonpath import jsonpath as jp
result = jp(data, "$.products[?(@.name =~ 'Laptop')]") # Example for libraries supporting regex
For jsonpath-rw, you'd typically do a two-step process or use a more complex predicate
For example, to find products containing 'Laptop' in their name:
expr = parse('products[*]') matches = expr.find(data)
filtered_products = [] for match in matches: if 'name' in match.value and 'Laptop' in match.value['name']: filtered_products.append(match.value)
print(json.dumps(filtered_products, indent=2))