'JsonPath: get root element depending on first level sub-element

I need all elements (including "id" and all attributes) of the json sample below where "type" has the value "state_machine_state", but only if "type" is on the first level. I don't want the middle element "order_transaction" in the result, although it has "type": "state_machine_state" in the second hierarchy level.

[
  {
    "id": "f45aa035eb424d26a0529d25b3647c32",
    "type": "state_machine_state",
    "attributes": {
      "technicalName": "cancelled",
      "name": "Cancelled",
      "stateMachineId": "7553ad2630044fa589d786135d5000ad",
      "customFields": null,
      "createdAt": "2020-06-05T14:23:30.503+02:00",
      "updatedAt": null,
      "translated": {
        "name": "Cancelled",
        "customFields": []
      },
      "apiAlias": null
    }
  },
  {
    "id": "2d24ed4179824dbe92eee2f3d4f885b1",
    "type": "order_transaction",
    "relationships": {
      "stateMachineState": {
        "data": {
          "type": "state_machine_state",
          "id": "21f236e8955f45d3931fc9e44615088a"
        }
      }
    },
    "meta": null
  },
  {
    "id": "d08e73da41b0473d83ea378a57a2fa1f",
    "type": "state_machine_state",
    "attributes": {
      "technicalName": "completed",
      "name": "Completed",
      "stateMachineId": "7553ad2630044fa589d786135d5000ad",
      "customFields": null,
      "createdAt": "2020-06-05T14:23:30.482+02:00",
      "updatedAt": null,
      "translated": {
        "name": "Completed",
        "customFields": []
      },
      "apiAlias": null
    },
    "meta": null
  }
]

With the query below I get all three elements

$..[?(@.type == 'state_machine_state')]

I just can't manage to select only the first level elements.

Could anyone please help?



Solution 1:[1]

Sometimes it helps to take a step back and think another way. With this query I get exactly what I want:

$..[?(@.type == 'state_machine_state' && @.attributes)]

The elements I need have attributes, the others don't, so I just check for that in the filter.

Solution 2:[2]

Some implementations will allow you to select several items, but you're not going to be able to get the values with their keys.

For example, if you do

$..[?(@.type == 'state_machine_state')['id','attributes']

You'll just get a result set that contains all of the id values and all of the attributes values.

[
  "f45aa035eb424d26a0529d25b3647c32",
  {
    "technicalName": "cancelled",
    "name": "Cancelled",
    "stateMachineId": "7553ad2630044fa589d786135d5000ad",
    "customFields": null,
    "createdAt": "2020-06-05T14:23:30.503+02:00",
    "updatedAt": null,
    "translated": {
      "name": "Cancelled",
      "customFields": []
    },
    "apiAlias": null
  },
  "2d24ed4179824dbe92eee2f3d4f885b1",
  "d08e73da41b0473d83ea378a57a2fa1f",
  {
    "technicalName": "completed",
    "name": "Completed",
    "stateMachineId": "7553ad2630044fa589d786135d5000ad",
    "customFields": null,
    "createdAt": "2020-06-05T14:23:30.482+02:00",
    "updatedAt": null,
    "translated": {
      "name": "Completed",
      "customFields": []
    },
    "apiAlias": null
  }
]

JSON Path isn't designed for transformation. JMES Path might be able to do what you're looking for, but I'm not as familiar with it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 M4tee
Solution 2 gregsdennis