Search code examples
javajsonpath

Filter nested json data using jsonpath as in example


I am using jsonpath to filter.

Json(Dummy json just to explain) source String, which is basically a list of Operating systems and details of its programs etc. In this example, the OS whose id = 1403 is a windows 10 OS and has 2 features acchritecture and browser. There are more details to the browser feature as shown in json

[
    {
        "id": 1403,
        "os": "window 10",
        "features": [
            {
                "id": 1356,
                "name": "architecture",
                "value": [
                    {
                        "id": 1308,
                        "feature": [
                            {
                                "id": 1262,
                                "key": "name",
                                "value": "amd64"
                            }
                        ]
                    }
                ],
                "category": "cat1"
            },
            {
                "id": 1357,
                "name": "browser",
                "value": [
                    {
                        "id": 1309,
                        "feature": [
                            {
                                "id": 1263,
                                "key": "name",
                                "value": "Firefox"
                            },
                            {
                                "id": 1265,
                                "key": "version",
                                "value": "187"
                            }
                        ]
                    }
                ],
                "category": "cat2"
            }
        ]
    },
    {
        "id": 2804,
        "os": "window 7",
        "features": [
            {
                "id": 2764,
                "name": "architecture",
                "value": [
                    {
                        "id": 2719,
                        "feature": [
                            {
                                "id": 2679,
                                "key": "name",
                                "value": "amd64"
                            }
                        ]
                    }
                ],
                "category": "cat1"
            },
            {
                "id": 2765,
                "name": "browser",
                "value": [
                    {
                        "id": 2722,
                        "feature": [
                            {
                                "id": 2685,
                                "key": "name",
                                "value": "Chrome"
                            },
                            {
                                "id": 2684,
                                "key": "version",
                                "value": "87.0.4280.88"
                            }
                        ]
                    }
                ],
                "category": "cat2"
            }
        ]
    }
]

I want to be able to filter the json such that

features[*].name == 'browser' and features[*].value[*].feature[*].value == 'chrome'

What will be the JsonPath string that can help me achieve above query? The above query uses similar syntax used by JsonPath string but doesn't do the job. Its just to explain.

There is another example here gets Movie Title Given 'Starring' field

And would like to get the full OS json that fulfils this condition. In this case a array of OS which contains only one OS i.e. with id= 2804

[
  {
    "id": "2804",
    ...
  }
]

I am stuck much before what aim to achieve. Here is my code to get all the OS that have "name=browser". I get the array but it only contains value[] items. I want it get the full json. It returns object with IDs- 1357, 2765.

List<Map<String, Object>> expensive = JsonPath.parse(jsonDataSourceString)
      .read("$[*].features[*].[?(@.name == 'browser')]");

Solution

  • To get the outer array you need to use the filter like $[?(...)]

    For your current use case, we need to use nested array filters. There is an open issue in JsonPath for filter on children level. (Refer here).

    Luckily, there is a workaround suggested to use contains over here.

    we can use the below expression to filter:

    List<Object> expensive = JsonPath.parse(jsonDataSourceString)
                                     .read("$[?(@.features[?(@.name == 'browser')].value[*].feature[*].value contains 'Chrome')]");
    

    Prints the below output

    {id=2804, os=window 7, features=[{"id":2764,"name":"architecture","value":[{"id":2719,"feature":[{"id":2679,"key":"name","value":"amd64"}]}],"category":"cat1"},{"id":2765,"name":"browser","value":[{"id":2722,"feature":[{"id":2685,"key":"name","value":"Chrome"},{"id":2684,"key":"version","value":"87.0.4280.88"}]}],"category":"cat2"}]}