1

I have this JSON as input:

{
  "users": {
    "alpha": [
      "read",
      "annotate",
      "write",
      "delete",
      "manage"
    ],
    "beta": [
      "read",
      "annotate",
      "write",
      "delete",
      "manage"
    ],
    "gamma": [
      "read",
      "annotate",
      "write",
      "delete"
    ],
    "delta": [
      "read",
      "annotate",
      "write",
      "delete",
      "manage"
    ]
  }
}

And I've been asked to return the lists (users) only if they contain the element manage. Since this has to be processed with Ansible filter json_query, it should use only the JMESPath query language.

Expected result is something like:

["alpha", "beta", "delta"]
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • 1
    You don't need jmespath for this in ansible => `{{ users | dict2items | selectattr('value', 'contains', 'manage') | map(attribute='key') }}` – Zeitounator Apr 22 '22 at 11:05
  • Thank you, @Zeitounator it's working! – Stefano Stagnaro Apr 22 '22 at 14:00
  • 1
    You won't find a pure JMESPath way to do it, I think. Getting keys in done with the `keys()` function on a dictionary, but it also destroys the possibility to query on the values. In the other hand, querying on a dictionary is possible with `users.*` but that, then, has the opposite behaviour by destroying the keys (it makes a list out of the dictionary, loosing the keys in the process). – β.εηοιτ.βε Apr 22 '22 at 18:08

1 Answers1

2

Try this

managers: "{{ users|dict2items|json_query(_query) }}"
_query: "[?contains(value, 'manage')].key"

It's an analogy to (credit @Zeitounator)

managers: "{{ users|dict2items|selectattr('value', 'contains', 'manage')| 
                               map(attribute='key') }}"

Q: "Do you always need a list?"

A: In most cases yes, but not always. It depends on what you want to achieve. For example, the dictionary is fine if you want to find out whether all users contain the element manage or not

all_users_manage: "{{ users|json_query(_query2) }}"
_query2: "*.contains(@, 'manage')"

gives

  all_users_manage:
  - true
  - true
  - false
  - true

Test the list

    - debug:
        msg: Not all users are managers.
      when: not all_users_manage is all

Or, you can find out whether any user contains the element manage

    - debug:
        msg: There are managers among the users.
      when: all_users_manage is any
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Thank you. I see that in both cases, the first step is to convert the dictionary into a list. It means that in order to perform selections, you always need a list, right? I was going crazy with JMESPath trying to query the elements of a dictionary. – Stefano Stagnaro Apr 22 '22 at 14:02
  • In [most cases](https://jmespath.org/examples.html) yes, but not always. I added an example. – Vladimir Botka Apr 22 '22 at 14:35