aldred
aldred

Reputation: 853

Nested loop with value comparison in Ansible

in the example below, how do I retrieve the grade of students listed in selected_students_list? I need to process the grade of the student. In other programming languages I can use nested loops but I'm a bit confused how to implement this in Ansible

---
- name: Test
  hosts: localhost
  vars:
    - all_students_list:
      - {
          name: "Charlie",
          grade: 9,
        }
      - {
          name: "Alice",
          grade: 8,
        }
      - {
          name: "Bob",
          grade: 7,
        }
      - {
          name: "Darla",
          grade: 10,
        }
      - {
          name: "Edith",
          grade: 11,
        }
    - selected_students_list:
       - Alice
       - Bob
  tasks:
    - name: Process selected students
      debug: 
        msg: "<PROCESS THE GRADE OF SELECTED STUDENTS i.e. Alice and Bob>"
      with_nested:
        -  "{{ all_students_list }}"
        -  "{{ selected_students_list }}"

Upvotes: 1

Views: 89

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68004

It's possible either to list selected students item by item. For example

    - name: Process selected students
      debug:
        msg: "PROCESS THE GRADES [{{ item.grade }}]
              OF SELECTED STUDENT {{ item.name }}"
      loop: "{{ all_students_list|
                selectattr('name', 'in', selected_students_list)|
                list }}"

gives

  msg: PROCESS THE GRADES [8] OF SELECTED STUDENT Alice
  msg: PROCESS THE GRADES [7] OF SELECTED STUDENT Bob

Or, to display the whole list at once. For example

    - name: Process selected students
      debug:
        msg: "{{ msg.split('\n')[:-1] }}"
      vars:
        my_list: "{{ all_students_list|
                     selectattr('name', 'in', selected_students_list)|
                     list }}"
        msg: |
          PROCESS THE GRADES OF SELECTED STUDENTS
          {{ my_list|to_yaml }}

gives

  msg:
  - PROCESS THE GRADES OF SELECTED STUDENTS
  - '- {grade: 8, name: Alice}'
  - '- {grade: 7, name: Bob}'


If the data is in a dictionary, instead of a list, the listing item by item is very simple. For example

- name: Test
  hosts: localhost
  vars:
    - all_students_dict:
        Charlie:
          grade: 9
        Alice:
          grade: 8
        Bob:
          grade: 7
        Darla:
          grade: 10
        Edith:
          grade: 11
    - selected_students_list:
       - Alice
       - Bob
  tasks:
    - name: Process selected students
      debug:
        msg: "PROCESS THE GRADES [{{ all_students_dict[item].grade }}]
              OF SELECTED STUDENT {{ item }}"
      loop: "{{ selected_students_list }}"

gives

  msg: PROCESS THE GRADES [8] OF SELECTED STUDENT Alice
  msg: PROCESS THE GRADES [7] OF SELECTED STUDENT Bob

It's possible to use filters dict2items and items2dict to create a dictionary of selected students. For example

    - name: Process selected students
      debug:
        msg: "{{ msg.split('\n')[:-1] }}"
      vars:
        my_dict: "{{ all_students_dict|
                     dict2items|
                     selectattr('key', 'in', selected_students_list)|
                     list|
                     items2dict }}"
        msg: |
          PROCESS THE GRADES OF SELECTED STUDENTS
          {{ my_dict|to_yaml }}

gives

  msg:
  - PROCESS THE GRADES OF SELECTED STUDENTS
  - 'Alice: {grade: 8}'
  - 'Bob: {grade: 7}

Upvotes: 1

Moon
Moon

Reputation: 3037

This should do

 vars:
    ...
    query: "[?name == `{{ item }}`].grade"
 tasks:
    - name: Process selected students
      debug:
        msg: "{{ all_students_list | json_query(query) }}"
      loop:  "{{ selected_students_list }}"

Check json-query-filter for more details.

Upvotes: 1

Related Questions