0

How can we create a code as below?

- name: TEST1
  set_fact:
    list_a: "{{ list_a + [item.json.SearchResult.resources] }}"
  with_items: 
    - "{{ source_list.results[0] }}"
    - "{{ source_list.results[1] }}"
    - "{{ source_list.results[x] }}"
    ... (unknown how many items in result from API)
  vars:
    list_a: []

source_list.results[x] comes from an API result. The reason why I need to create an array is that the number of API result is maximum 100. But there are over 500 items.

2
  • 1
    This sounds like your going about it the wrong way. Is your end result you want list_a to just be a nested list of source_list.results[0].json.SearchResult.resources from 0 to x items? Commented Dec 4, 2022 at 1:00
  • 1
    something like loop: "{{ source_list | community.general.json_query('results[*].json.SearchResult.resources') }}" Commented Dec 4, 2022 at 1:08

2 Answers 2

2

You are taking this the wrong way. Simply extract the attribute you need from each result using the map(attribute=x) Jinja2 filter.

Since you did not provide an example data structure, I inferred below that:

  • you called your API with ansible.builtin.uri in a loop to get batches of 100 results which are returned as a list in the SearchResult.ressources field
  • you want in the end a flattened list where all resources are at top level
- name: Show my list of single attributes
  ansible.builtin.debug:
    var: "source_list.results
      | map(attribute='json.SearchResult.resources') | flatten"

You actually don't need to set_fact:

  • For a single use, just use the above expression directly in the relevant parameter (e.g. loop or a module param....) or eventually declare this in a var at task level.
  • If you want to reuse this in different parts of your playbook, just declare a var at play level and expand it anywhere once you have called your API and populated the source_list var. In that case, just add a default value to prevent an error if API was not yet called.

Example for the second case above in this pseudo playbook

---
- hosts: localhost
  gather_facts: false

  vars:
    list_a: "{{ source_list.results | d([])
      | map(attribute='json.SearchResult.resources') | flatten }}"

  tasks:
    - name: "This will return an empty list (i.e. [])
        as we did not populate source_list yet"
      ansible.builtin.debug:
        var: list_a

    - name: Call our API and register source_list
      ansible.builtin.uri:
        uri: https://my.api.com/api/v1/some/endpoint
        # [... more parameters here ... ]
      loop: "{{ my_list_of_ressources }}"
      register: source_list

    - name: "This will now return a populated list
        after calling the API and registering source_list"
      ansible.builtin.debug:
        var: list_a

Now, to still give a direct answer to your initial question: you can construct that list iteratively inside a set_fact task. This is definitely not efficient as it involves a task running inside a loop (both unneeded as demonstrated above) and possibly on multiple hosts in your play. But for learning purpose, here it is:

- name: very inefficient way to get the same result as above
  set_fact:
    list_a: "{{ list_a | d([]) + item.SearchResult.resources }}"
  loop: "{{ source_list.results }}"
Sign up to request clarification or add additional context in comments.

Comments

0

After reading @Zeitounator's answer, I realized I was taking this the wrong way. I used the idea in the answer (json query and flatten) and I changed my task to the below which works as expected.

- name: Create ID list from API result data
  set_fact:
    list_a: "{{ source_list | json_query('results[*].json.SearchResult.resources[*].id') | flatten }}"
    
- name: API get again with id
  uri:
    url: "{{ request_url }}/{{ item }}"
    ... 
  register: result_data
  with_items:
    - "{{ list_a }}"

1 Comment

We still have no knowledge of your initial data structure which makes this specific answer a bit useless. Please edit your question with a correct minimal reproducible example to make all this more useful for future users. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.