Search code examples
ansiblejmespathjson-query

Combine attribute value using json_query in ansible


I want to combine two attribute into single string separated by delimiter using the json_query in ansible
Sample data

{
  "locations": [
    {"name": "Seattle", "state": "WA"},
    {"name": "New York", "state": "NY"},
    {"name": "Bellevue", "state": "WA"},
    {"name": "Olympia", "state": "WA"}
  ]
}

As shown in above data set i'm trying to filter the state "WA" and execpted output is:

[
    "Seattle-WA",
    "Bellevue-WA",
    "Olympia-WA"
]

What i have tried as of now:

    - debug:
        msg: "{{ chart_list.HELM_CHARTS | json_query(\"[?state == 'WA'].{name:name,state:state}\") }}"
Output:
[
  {
    "name": "Seattle",
    "state": "WA"
  },
  {
    "name": "Bellevue",
    "state": "WA"
  },
  {
    "name": "Olympia",
    "state": "WA"
  }
]

Updated : I was able to get the expected result by trial and error method and these are my findings:

[?state == 'WA'].[join('-',[name,state])][]
Output:
[
  "Seattle-WA",
  "Bellevue-WA",
  "Olympia-WA"
]

Also if the input which you give is in unicode format, i suggest you to add to_json | from_json expressions as mentioned below:

        selected_cities: "{{ test.locations| to_json | from_json | json_query(\"[?state == 'WA'].[join('-',[name,state])][]\") }}"

Using above expression will eliminate unicode error whil using the values or in any condition. Check JMESPath site for more detail on the json_query, it was really helpful in resolving the issue.


Solution

  • For example

        - debug:
            msg: "{{ locations|
                     json_query('[?state == `WA`].[name,state]')|
                     map('join', '-')|list }}"
    

    gives

      msg:
      - Seattle-WA
      - Bellevue-WA
      - Olympia-WA
    

    The same result gives the task below using Jinja2 filters only

        - debug:
            msg: "{{ _names|zip(_states)|map('join', '-')|list }}"
          vars:
            _locations: "{{ locations|selectattr('state', 'eq', 'WA')|list }}"
            _names: "{{ _locations|map(attribute='name')|list }}"
            _states: "{{ _locations|map(attribute='state')|list }}"
    

    json_query issue (fixed in 2.10 and later)

    There is JMESPath join. Unfortunately

        - debug:
            msg: "{{ locations|
                     json_query('[].join(`-`, [name,state])') }}"
    

    fails

    msg: |- JMESPathError in json_query filter plugin: In function join(), invalid type for value: Seattle, expected one of: ['array-string'], received: "AnsibleUnicode"

    to_json|from_json workaround

    Quoting from json_query: Add examples for starts_with and contains #72821

    data structure returned from register variables needs to be parsed using to_json | from_json in order to get a correct result. Fixes: ansible-collections/community.general#320

        - debug:
            msg: "{{ locations|to_json|from_json|
                     json_query('[].join(`-`, [name,state])') }}"
    

    gives

      msg:
      - Seattle-WA
      - New York-NY
      - Bellevue-WA
      - Olympia-WA