Search code examples
ansiblejmespathjson-query

Extract JSON value with key containing dashes and provided via an Ansible variable


I am trying to retrieve a value from a JSON in Ansible, where the key contains dashes and is provided via a variable.


I have the following data in Ansible:

- set_fact:
    data: >-
      {
        "profile-id": 1234, "user_id": 6789
      }

It is known that to retrieve profile-id, one has to quote the key, for example:

- set_fact:
    value: >-
      {{ data | json_query("profile-id") }}

How could I retrieve the value, if profile-id is registered in a variable?

For example, with the following variable:

- set_fact:
    lookup_key: profile-id

I have tried different approaches, none of them working:

  • json_query("lookup_key") does not substitute the lookup key
  • json_query(\"lookup_key\") attempts to look up "profile-id" instead of profile-id, returning no results.
  • json_query(lookup_key | regex_replace('[-]', '\\-')) returns the error: Unknown token \\.

How should I handle this?


Solution

  • Mind that your variable data does contains the string representation of a JSON, and not a JSON.

    Since Ansible is very much JSON capable and that YAML is a superset of JSON, your data fact could benefit from being expressed as a JSON or a YAML:

    # expressed as a JSON:
    data: {
      "profile-id": 1234, "user_id": 6789
    }
    # or expressed as a YAML:
    data:
      profile-id: 1234
      user_id: 6789
    

    Which would make your task of accessing it trivial:

    - set_fact:
        value: "{{ data[lookup_key] }}"
      vars:
        lookup_key: profile-id
    

    Which results in

    ok: [localhost] => changed=false 
      ansible_facts:
        value: '1234'
    

    Note: the above output was generated running the playbook with the option -v, which, amongst other useful information, shows the result of a set_fact task.


    Now, if you do receive a string representation of a JSON from another task or from a API query, then you can use the from_json filter to parse the string into a real JSON, where

    - set_fact:
        value: >-
          {{ (data | from_json)[lookup_key] }}
      vars:
        lookup_key: profile-id
        data: >-
          { "profile-id": 1234, "user_id": 6789 }
    

    Also results in value being set to 1234


    As for your JMESPath query, you are right that a JSON identifier with dash has to be queried using double quote in the query itself, but that means that the double quote have to be part of the lookup_key variable!

    So, you could use simple quote to delimit the lookup_key value. Or use the folded syntax again:

    # with simple quote:
    lookup_key: '"profile-id"'
    # with the folded syntax:
    lookup_key: >-
      "profile-id"
    

    So your tasks could look like:

    - set_fact:
        value: >-
          {{ data | json_query(lookup_key) }}
      vars:
        lookup_key: >-
          "profile-id"
        data:
          profile-id: 1234
          user_id: 6789