Reputation: 625
I've a csv file which i'm reading as a dict using Ansible read_csv
id,name,quantity,type
1,apple,10,fruit
2,orange,20,fruit
3,carrot,5,veg
4,beetroot,2,veg
5,onion,3,veg
6,tomato,4,both
7,pear,4,fruit
8,banana,6,fruit
9,persimon,4,fruit
10,guava,4,fruit
11,pepper,4,veg
12,potato,5,veg
13,cherry,5,fruit
The equivalent dict becomes
"{'1': {'id': '1', 'name': 'apple', 'quantity': '10', 'type': 'fruit'}, '2': {'id': '2', 'name': 'orange', 'quantity': '20', 'type': 'fruit'}, '3': {'id': '3', 'name': 'carrot', 'quantity': '5', 'type': 'veg'}, '4': {'id': '4', 'name': 'beetroot', 'quantity': '2', 'type': 'veg'}, '5': {'id': '5', 'name': 'onion', 'quantity': '3', 'type': 'veg'}, '6': {'id': '6', 'name': 'tomato', 'quantity': '4', 'type': 'both'}, '7': {'id': '7', 'name': 'pear', 'quantity': '4', 'type': 'fruit'}, '8': {'id': '8', 'name': 'banana', 'quantity': '6', 'type': 'fruit'}, '9': {'id': '9', 'name': 'persimon', 'quantity': '4', 'type': 'fruit'}, '10': {'id': '10', 'name': 'guava', 'quantity': '4', 'type': 'fruit'}, '11': {'id': '11', 'name': 'pepper', 'quantity': '4', 'type': 'veg'}, '12': {'id': '12', 'name': 'potato', 'quantity': '5', 'type': 'veg'}, '13': {'id': '13', 'name': 'cherry', 'quantity': '5', 'type': 'fruit'}}"
My logic was to split the list into batches of 2 name per type at a time
So output I was looking for is ["carrot", "beetroot"], ["onion", "pepper"]
and so on
The below logic works perfectly when i hardcode the [0:2]
range in the jinja expression
{% set my_fruit_list = [] %}
{%- for item in (fruits_dict.dict| dict2items | selectattr("value.type", "match", "^veg$"))[0:2] -%}
{{ my_fruit_list.append(item.value.name) }}
{%- endfor -%}
my_list=["{{ my_fruit_list|join('", "') }}"]
But when i try changing it to a dynamic variable, it doesn't work. I tried below
{% set input_range = "[0:2]" %}
{%- for item in (fruits_dict.dict| dict2items | selectattr("value.type", "match", "^veg$"))input_range -%}
Is there any way we can pass the "input_range" as a dynamic parameter into the expression?
Also is there a better way of getting the selectattr
without converting the csv to dict
and dict2items
?
Upvotes: 2
Views: 255
Reputation: 68074
Given the file Read the file and create a dictionary by the key id givesshell> cat /tmp/fruits.csv
id,name,quantity,type
1,apple,10,fruit
2,orange,20,fruit
3,carrot,5,veg
4,beetroot,2,veg
5,onion,3,veg
6,tomato,4,both
7,pear,4,fruit
8,banana,6,fruit
9,persimon,4,fruit
10,guava,4,fruit
11,pepper,4,veg
12,potato,5,veg
13,cherry,5,fruit
- read_csv:
path: /tmp/fruits.csv
key: id
register: fruits
fruits.dict:
'1': {id: '1', name: apple, quantity: '10', type: fruit}
'10': {id: '10', name: guava, quantity: '4', type: fruit}
'11': {id: '11', name: pepper, quantity: '4', type: veg}
'12': {id: '12', name: potato, quantity: '5', type: veg}
'13': {id: '13', name: cherry, quantity: '5', type: fruit}
'2': {id: '2', name: orange, quantity: '20', type: fruit}
'3': {id: '3', name: carrot, quantity: '5', type: veg}
'4': {id: '4', name: beetroot, quantity: '2', type: veg}
'5': {id: '5', name: onion, quantity: '3', type: veg}
'6': {id: '6', name: tomato, quantity: '4', type: both}
'7': {id: '7', name: pear, quantity: '4', type: fruit}
'8': {id: '8', name: banana, quantity: '6', type: fruit}
'9': {id: '9', name: persimon, quantity: '4', type: fruit}
by_type: "{{ fruits.dict.values()|groupby('type') }}"
gives
by_type:
- - both
- - {id: '6', name: tomato, quantity: '4', type: both}
- - fruit
- - {id: '1', name: apple, quantity: '10', type: fruit}
- {id: '2', name: orange, quantity: '20', type: fruit}
- {id: '7', name: pear, quantity: '4', type: fruit}
- {id: '8', name: banana, quantity: '6', type: fruit}
- {id: '9', name: persimon, quantity: '4', type: fruit}
- {id: '10', name: guava, quantity: '4', type: fruit}
- {id: '13', name: cherry, quantity: '5', type: fruit}
- - veg
- - {id: '3', name: carrot, quantity: '5', type: veg}
- {id: '4', name: beetroot, quantity: '2', type: veg}
- {id: '5', name: onion, quantity: '3', type: veg}
- {id: '11', name: pepper, quantity: '4', type: veg}
- {id: '12', name: potato, quantity: '5', type: veg}
my_dict: "{{ dict(by_type|map('first')|list|
zip(by_type|map('last')|
map('map', attribute='name')|list)) }}"
gives
my_dict:
both: [tomato]
fruit: [apple, orange, pear, banana, persimon, guava, cherry]
veg: [carrot, beetroot, onion, pepper, potato]
my_list: |
{% for batch in my_dict[type]|batch(input_range|int) %}
- {{ batch }}
{% endfor %}
For example, the loop below
- debug:
msg: "{{ my_list }}"
loop: "{{ my_dict.keys()|list }}"
vars:
type: "{{ item }}"
for input_range=2
gives
TASK [debug] **************************************************************
ok: [localhost] => (item=both) =>
msg: |2-
- ['tomato']
ok: [localhost] => (item=fruit) =>
msg: |2-
- ['apple', 'orange']
- ['pear', 'banana']
- ['persimon', 'guava']
- ['cherry']
ok: [localhost] => (item=veg) =>
msg: |2-
- ['carrot', 'beetroot']
- ['onion', 'pepper']
- ['potato']
for input_range=3
gives
TASK [debug] **************************************************************
ok: [localhost] => (item=both) =>
msg: |2-
- ['tomato']
ok: [localhost] => (item=fruit) =>
msg: |2-
- ['apple', 'orange', 'pear']
- ['banana', 'persimon', 'guava']
- ['cherry']
ok: [localhost] => (item=veg) =>
msg: |2-
- ['carrot', 'beetroot', 'onion']
- ['pepper', 'potato']
- set_fact:
my_list_veg: "{{ my_list }}"
vars:
type: veg
input_range: 3
- debug:
var: my_list_veg
gives
my_list_veg:
- ['carrot', 'beetroot', 'onion']
- ['pepper', 'potato']
shell> cat pb.yml
- hosts: localhost
vars:
input_range: 2
by_type: "{{ fruits.dict.values()|groupby('type') }}"
my_dict: "{{ dict(by_type|map('first')|list|
zip(by_type|map('last')|
map('map', attribute='name')|list)) }}"
my_list: |
{% for batch in my_dict[type]|batch(input_range|int) %}
- {{ batch }}
{% endfor %}
tasks:
- read_csv:
path: /tmp/fruits.csv
key: id
register: fruits
- debug:
var: fruits.dict|to_yaml
- debug:
var: by_type|to_yaml
- debug:
var: my_dict|to_yaml
- debug:
msg: "{{ my_list }}"
loop: "{{ my_dict.keys()|list }}"
vars:
type: "{{ item }}"
- set_fact:
my_list_veg: "{{ my_list }}"
vars:
type: veg
input_range: 3
- debug:
var: my_list_veg
shell> ansible-playbook pb.yml -e input_range=3
A: Create a dictionary with all attributes
my_dict: "{{ dict(by_type) }}"
gives
my_dict:
both:
- {id: '6', name: tomato, quantity: '4', type: both}
fruit:
- {id: '1', name: apple, quantity: '10', type: fruit}
- {id: '2', name: orange, quantity: '20', type: fruit}
- {id: '7', name: pear, quantity: '4', type: fruit}
- {id: '8', name: banana, quantity: '6', type: fruit}
- {id: '9', name: persimon, quantity: '4', type: fruit}
- {id: '10', name: guava, quantity: '4', type: fruit}
- {id: '13', name: cherry, quantity: '5', type: fruit}
veg:
- {id: '3', name: carrot, quantity: '5', type: veg}
- {id: '4', name: beetroot, quantity: '2', type: veg}
- {id: '5', name: onion, quantity: '3', type: veg}
- {id: '11', name: pepper, quantity: '4', type: veg}
- {id: '12', name: potato, quantity: '5', type: veg}
Then, select the attributes you want. For example, select the attributes id and name and create the template
my_list: |
{% for batch in my_dict[type]|batch(input_range|int) %}
{% for i in batch %}
- id: {{ i.id }}
name: {{ i.name }}
{% endfor %}
{% endfor %}
Then create specific lists, for example
- set_fact:
my_list_veg: "{{ my_list|from_yaml }}"
vars:
type: veg
input_range: 3
- debug:
var: my_list_veg
gives
my_list_veg:
- {id: 3, name: carrot}
- {id: 4, name: beetroot}
- {id: 5, name: onion}
- {id: 11, name: pepper}
- {id: 12, name: potato}
Upvotes: 1
Reputation: 44615
In a nutshell:
{% set my_fruit_list = [] %}
{% set fruit_start = 0 %}
{% set fruit_end = 1 %}
{%- for item in (fruits_dict.dict| dict2items | selectattr("value.type", "match", "^veg$"))[fruit_start:fruit_end] -%}
{{ my_fruit_list.append(item.value.name) }}
{%- endfor -%}
my_list=["{{ my_fruit_list|join('", "') }}"]
Upvotes: 1