How to match a regex on an array name itself in jmespath (json element string regex wildcard)
Asked Answered
M

1

3

How can I search for an array in a json using a regex in jmespath?

Consider the following JSON document (set aside if it's poorly constructed):

{
  "people_in_town": [
    {"letter": "a"},
    {"letter": "b"},
  ],
  "people_with_shoes": [
    {"letter": "c"},
    {"letter": "d"},
  ],
  "people_with_town": [
    {"letter": "e"},
    {"letter": "f"},
  ],
}

Now, jmespath makes it easy to do a wildcard on all of the elements of the list such that people_in_town[*].letter would return [a, b].

But the wildcard I want to use is a regex on the name of the arrays as follows:

people_*_town.letter

Such that it would return the contents of people_in_town and people_with_town and any array that has people_ followed by <some string> followed by _town. The above example, of course, doesn't work.

How can I match an array in a json document with a regex using jmespath?

Metallophone answered 17/3, 2021 at 16:44 Comment(4)
See also devops.stackexchange.com/questions/13564/…Metallophone
Is your use case to really do foo_*_bar (note this is a wildcard and not a regex, actually) or to do foo_abc_bar OR foo_def_bar OR foo_ghi_bar? When the first one will most likely not be possible, the second one, is definitly.Fridafriday
This question was created for the first, which is glaringly absent from the jmespath documentation. I used a wildcard for simplicity, but a regex would be preferred.Metallophone
There is no such a thing as regex in JMESPath. Though there is a ticket open to try to fit it in: github.com/jmespath/jmespath.py/issues/213Fridafriday
F
1

This is just covering the use case you added from your linked question, and not the really generic wildcard in a key question, that will most likely not be possible.

But in case you indeed have something to query like

key in ['people_in_town', 'people_with_town']

So, with a finite number of know keys, then you can definitely do something like

[@.people_in_town, @.people_with_town][].letter

That would give:

[
  "a",
  "b",
  "e",
  "f"
]

The main issue you'll face with a pure JMESPath approach is that the only actions you can do on keys is based on the keys function, and sadly is is not possible to have both the array of keys and then come back to the part to select those keys.

If you really want to resort to only JMESPath, then, you'll have to end with two pass:

  1. Create the list of keys with keys and the starts_with/ends_with functions
  2. Then do a second pass to come back to the query as stated above

In an Ansible point of view this ends up with this utterly ugly playbook:

- hosts: all
  gather_facts: no

  tasks:
    - debug: 
        msg: >-
          {{
              data | json_query(
                "[@." ~ data | json_query(
                  "join(
                    ',@.', 
                    keys(@)[?
                      starts_with(@, 'people_') 
                      && ends_with(@, '_town')
                    ]
                  )"
                ) ~ "][].letter"
              )
          }}
      vars:
        data:
          people_in_town:
            - letter: a
            - letter: b
          people_with_shoes:
            - letter: c
            - letter: d
          people_with_town:
            - letter: e
            - letter: f

That yields

PLAY [all] *******************************************************************************************

TASK [debug] *****************************************************************************************
ok: [localhost] => 
  msg:
  - a
  - b
  - e
  - f

PLAY RECAP *******************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

So, really if I were you, I would stick to the option proposed in the answers of the linked question and stay away from JMESPath for this specific use case.

Freedom answered 17/3, 2021 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.