Search code examples
jmespath

How do I do a contains expression in a nested object?


this is my json

{
  "items": [
      "top": {
        "first": "test",
        "second": {
          "third": "test",
        },
        ...

This returns all items where top.first contains test:

items[?contains(top.first, `test`)]

This returns an error:

items[?contains(top.second.third, `test`)]

TypeError: contains() expected argument 1 to be type (string | array) but received type null instead.

This works with a explict ==, but for some reason contains() is throwing the above error

items[?top.second.third == `test`]

How do I query one level lower here?


Solution

  • Here is what I suspect: you do have some items in your JSON array that either do not have the top.second property or do not have the top.second.third property.

    So, here is my base JSON to try to reproduce your issue, where you can see I do have the three cases:

    • one element with no second property
    • one element with a second property, but no third property nested in second
    • one element with a second property and a third property nested in second
    {
      "items": [
        {
          "top": {
            "first": "test"
          }
        },
        {
          "top": {
            "first": "test",
            "second": {}
          }
        },
        {
          "top": {
            "first": "test",
            "second": {
              "third": "test"
            }
          }
        }
      ]
    }
    

    With all this, we can demonstrate that it is fairly easy to achieve what you want, since we just have to first check that all those property do exists with a simple [?top.second.third] before adding our contains statement.

    Ending with the query:

    items[?top.second.third && contains(top.second.third, `test`)]
    

    That yields, as we would expect:

    [
      {
        "top": {
          "first": "test",
          "second": {
            "third": "test"
          }
        }
      }
    ]