Home > Enterprise >  JMESPath filter for elements with nested values starting with certain string
JMESPath filter for elements with nested values starting with certain string

Time:09-04

I have the following JSON structure:

[
    {
        "stack": [
            "datasync"
        ],
        "env": [
            "dev",
            "test"
        ],
        "runOnBranch": [
            "feature/",
            "bugfix/",
            "develop"
        ]
    },
    {
        "stack": [
            "datasync"
        ],
        "env": [
            "val",
            "prod"
        ],
        "runOnBranch": [
            "main"
        ]
    }
]

And I would like to filter the list based on if a given string starts with one of the strings defined in the runOnBranch attribute.

My best guess so far doesn't work:

[?runOnBranch.starts_with(@, `feature/`) == `true`]

The error I get is:

"Search parse error": TypeError: starts_with() expected argument 1 to be type 2 but received type 3 instead.

The result I would like to get is:

[
    {
        "stack": [
            "datasync"
        ],
        "env": [
            "dev",
            "test"
        ],
        "runOnBranch": [
            "feature/",
            "bugfix/",
            "develop"
        ]
    }
]

What am I missing?

CodePudding user response:

In order to assess that there is one element in the array that starts with something you will need to:

  1. assess each string in the array, effectively creating a list of boolean, so, with starts_with but targeting each string, not the whole array:
    runOnBranch[].starts_with(@, `feature/`),
    
  2. assess that there is at least one true value contained in the resulting array, with the help of the contains function
    contains(runOnBranch[].starts_with(@, `feature/`), `true`)
    
  3. and finally put all this in your filter

So, we end with the query:

[?contains(runOnBranch[].starts_with(@, `feature/`), `true`)]

Which yields:

[
  {
    "stack": [
      "datasync"
    ],
    "env": [
      "dev",
      "test"
    ],
    "runOnBranch": [
      "feature/",
      "bugfix/",
      "develop"
    ]
  }
]

And to be more coherent in notation, this can also be written as:

[?(runOnBranch[].starts_with(@, `feature/`)).contains(@, `true`)]

Side note: simplify those kind of filter:

[?runOnBranch.starts_with(@, `feature/`) == `true`]

to

[?runOnBranch.starts_with(@, `feature/`)]

as starts_with already returns a boolean, as documented in the function signature:

boolean starts_with(string $subject, string $prefix)

Source: https://jmespath.org/specification.html#starts-with

  • Related