dfs
dfs

Reputation: 182

Ansible: Extract a value from a dictionary in a list

I have a task to extract the ID value of VM's through the uri module, using Ansible 2.9 . I save the result into a variable called uri_comp The structure of the output of uri_comp that i need to extract a value from is as such: I had to manually recreate this, so indentation might not be 100% correct.

"results": [ 
   { 
        "json": {
            "computers": [
                {
                    "ID": 1167,
                    "agentFingerPrint": "editedvalue",
                    "agentGUID": "editedvalue",
                    "agentVersion": "editedvalue",
                    "biosUUID": "editedvalue",
                    "description": "",
                    "displayName": "",
                    "groupID": 0,
                    "hostGUID": "editedvalue",
                    "hostName": "editedvalue",
                    "lastAgentCommunication": editedvalue,
                    "lastIPUsed": "editedvalue",
                    "platform": "",
                    "policyID": editedvalue,
                    "relayListID": 0
                 }
                         ]
   },



             "computers": [
                {
                    "ID": 27,
                    "agentFingerPrint": "editedvalue",
                    "agentGUID": "editedvalue",
                    "agentVersion": "editedvalue",
                    "biosUUID": "editedvalue",
                    "description": "",
                    "displayName": "",
                    "groupID": 0,
                    "hostGUID": "editedvalue",
                    "hostName": "editedvalue",
                    "lastAgentCommunication": editedvalue,
                    "lastIPUsed": "editedvalue",
                    "platform": "",
                    "policyID": editedvalue,
                    "relayListID": 0
                 }
                         ]
   },

I need a variable set as a set fact which contains as in underneath output just the comp_id number. So in this case:

comp_id:
   - 17
   - 1167  

I extract the computers ID value with a lot of extra looping clutter, in this way.

        - name: "Print ID of computers"
          debug:
            msg: "{{ item|json_query('json.computers')|map(attribute='ID') }}"
          loop: "{{ uri_comp|json_query('results') }}"

output:

TASK [Print ID of computers] **********************************************************************************************************
ok: [localhost] => (item={'content': '{"computers":[{CLUTTER}) => { CLUTTER CLUTTER CLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTER
    "msg": [
        17
    ]
}
ok: [localhost] => (item={'content': '{"computers":[{CLUTTER}) => { CLUTTER CLUTTER CLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTERCLUTTER
    "msg": [
        1167
    ]
}

I manage to extract the values with the debug but once i try and save this into a variable with set_fact, it gets overwritten by the loop and i loose the first ID value.

        - set_fact:
            comp_ID: "{{ item|map(attribute='ID') }}"
          loop: "{{ uri_comp|json_query('results[*].json.computers') }}"

Type of data for computers is a list. Which i checked with type_debug. If i'm not wrong i believe that inside the list there's a dictionary. Probably that's where my issue is.

When googling " how to extract a value from a list of dictionary" i find interesting things but nothing leading towards a solution.

So i've been told to do this without a loop which does not work, i manage to map the attribute until computers but then whatever i tried does not work.

        - set_fact:
            comp_ID: "{{ uri_comp.results|map(attribute='json')|map(attribute='computers')}}"

output:

ok: [localhost] => {
    "msg": [
        [
            {
                "ID": 17,
                "agentFingerPrint": "0editedvalue",
                "agentGUID": "editedvalue",
                "agentVersion": "editedvalue",
                "biosUUID": "editedvalue",
                "description": "",
                "displayName": "",
                "groupID": 0,
                "hostGUID": "editedvalue",
                "hostName": "editedvalue",
                "lastAgentCommunication": editedvalue,
                "lastIPUsed": "editedvalue",
                "platform": "",
                "policyID": 10,
                "relayListID": 0
            }
        ],
        [
            {
                "ID": 1167,
                "agentFingerPrint": "editedvalue",
                "agentGUID": "editedvalue",
                "agentVersion": "editedvalue",
                "biosUUID": "editedvalue",
                "description": "",
                "displayName": "",
                "groupID": 0,
                "hostGUID": "editedvalue",
                "hostName": "editedvalue",
                "lastAgentCommunication": editedvalue,
                "lastIPUsed": "editedvalue",
                "platform": "",
                "policyID": 10,
                "relayListID": 0
            }
        ]
    ]
}

I tried:

        - set_fact:
            comp_ID: "{{ uri_comp.results|map(attribute='json')|map(attribute='computers')|map(attribute='ID') }}"

output:

TASK [debug set_fact] *****************************************************************************************************************
ok: [localhost] => {
    "msg": "[AnsibleUndefined, AnsibleUndefined]"
}

I tried:

        - set_fact:
            comp_ID: "{{ uri_comp.results|map(attribute='json')|map(attribute='computers')|json_query('ID')}}"

output:

ok: [localhost] => {
    "msg": ""
}

I tried dot notation,

        - set_fact:
            comp_ID: "{{ uri_comp.results.json.computers }}"

I tried also to use items2dict filter wihtout any success. I also tried dict2items as in this post Extract values from a list of dictionaries in Ansible I tried selectattr('ID', defined) I've seen lots of similar questions on this site and on google, though none seemed to fit my issue. https://sleeplessbeastie.eu/2022/09/26/how-to-lookup-specific-element-in-ansible-dictionary-or-list-of-these/ Which leads me to think that i have something fundamentally wrong here. Is this really possible without a loop? I would be most grateful to read which tool i should use or which data structure this is or any leads really.

Upvotes: 0

Views: 2057

Answers (1)

Zeitounator
Zeitounator

Reputation: 44799

I had to manually recreate this, so indentation might not be 100% correct.

It is your responsibility to create a correct minimal reproducible example. In this case not only the indentation (crucial for yaml but not so important for pure json) but the entire structure is wrong. I guessed the below structure in my example from your code samples and current results but I cannot guaranty it sticks exactly to yours.

Please systematically check, lint and fix your data examples and make sure they are correct.


The following playbook

---
- hosts: localhost
  gather_facts: false

  vars:
    uri_comp: {
      "results": [ 
        { 
          "json": {
              "computers": [
                  {
                      "ID": 1167,
                      "agentFingerPrint": "editedvalue",
                      "agentGUID": "editedvalue",
                      "agentVersion": "editedvalue",
                      "biosUUID": "editedvalue",
                      "description": "",
                      "displayName": "",
                      "groupID": 0,
                      "hostGUID": "editedvalue",
                      "hostName": "editedvalue",
                      "lastAgentCommunication": editedvalue,
                      "lastIPUsed": "editedvalue",
                      "platform": "",
                      "policyID": editedvalue,
                      "relayListID": 0
                   }
              ]
          }
        },
        {
           "json": {
             "computers": [
                {
                    "ID": 27,
                    "agentFingerPrint": "editedvalue",
                    "agentGUID": "editedvalue",
                    "agentVersion": "editedvalue",
                    "biosUUID": "editedvalue",
                    "description": "",
                    "displayName": "",
                    "groupID": 0,
                    "hostGUID": "editedvalue",
                    "hostName": "editedvalue",
                    "lastAgentCommunication": editedvalue,
                    "lastIPUsed": "editedvalue",
                    "platform": "",
                    "policyID": editedvalue,
                    "relayListID": 0
                 }
             ]
          }
        }
      ]
    }    

    comp_ID: "{{ uri_comp.results | map(attribute='json.computers') | flatten | map(attribute='ID') }}"

  tasks:
    - debug:
        var: comp_ID

gives:

PLAY [localhost] **************************************************************************************************************************************************************************************************

TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "comp_ID": [
        1167,
        27
    ]
}

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

Upvotes: 3

Related Questions