JSONPath :contains filter

Learn jsonpath :contains filter with practical examples, diagrams, and best practices. Covers javascript, jquery, regex development techniques with visual explanations.

Mastering JSONPath's :contains Filter for Dynamic Data Selection

Hero image for JSONPath :contains filter

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 of property contains the specified 'substring'.

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

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))