I'm trying to parse json in ansible and I got the value I need but the output is an array. How can I get just the value?
Example json:
{
"Version": "2015-08-13",
"Accounts": [{
"AccountName": "account1",
"Regions": [{
"RegionName": "region1",
"RegionId": "region1",
"RegionDetails": [{
"id": "id1",
"version": "v1"
}, {
"id": "id2",
"version": "v2"
}]
}]
}, {
"AccountName": "account2",
"Regions": [{
"RegionName": "region1",
"RegionId": "region1",
"RegionDetails": [{
"id": "id1",
"version": "v1"
}, {
"id": "id2",
"version": "v2"
}]
}]
}]
}
Ansible playbook example:
- name: Set Global Vars
hosts: localhost
tasks:
- name: print json file
debug:
msg: "{{ (lookup('file','./example.json') | from_json) | json_query(query) }}"
vars:
query: "Accounts[?AccountName=='account1'][Regions[?RegionName=='region1'].RegionId]"
register: region_id
Ansible output:
TASK [print json file] *********************************************************
ok: [localhost] => {
"msg": [
[
[
"region1"
]
]
]
}
As you can see the value 'region1' is still nested. How can I get just the value out?
Thanks!
Your original data has nested lists: Accounts is a list, each account contains Regions list.
With your JMESPath query you filter lists by some criteria, but result is still a list, because your data may have more then one account with name AccountName=='account1'.
If you are interested only in first found account and first found region of that account, you can modify query as follows:
Accounts[?AccountName=='account1'] | [0].Regions[?RegionName=='region1'] | [0].RegionId
Related
How can I merge dictionaries within the list with the some properties that are the same and have the values of the properties that are different added to a list value of merged dictionary?
[
{
"name": "samename",
"content": "content1"
},
{
"name": "samename",
"content": "content2"
},
{
"name": "differentname",
"content": "content3"
}
]
Desired output:
[
{
"name": "samename",
"content": ["content1", "content2"]
},
{
"name": "differentname",
"content": "content3"
}
]
Given the data
data:
- content: content1
name: samename
- content: content2
name: samename
- content: content3
name: differentname
Use the filter json_query to create lists from the attribute content. Then use the filter community.general.lists_mergeby to merge the items, e.g.
data_groups_query: '[].{name: name, content: [content]}'
data_groups: "{{ [data|json_query(data_groups_query), []]|
community.general.lists_mergeby('name', list_merge='append') }}"
gives what you want
data_groups:
- content: [content3]
name: differentname
- content: [content1, content2]
name: samename
I'm having trouble to get ID from json code that mutch a specific value in such array
I explain:
I have this code json:
{
"results": [
{
"TAB": "bleu",
"exp": [
{
"A": "NOT_PROTECTED",
"B": [
"500",
"600"
],
"C": false
}
],
"ID": "000041"
},
{
"TAB": "rouge",
"exp": [
{
"A": "PROTECTED",
"B": [
"700",
"800"
],
"C": true
}
],
"ID": "000042"
}
]
}
I'm assuming the question is how you access the values in Ansible, since it has the ansible tag.
You can use the map filter in Ansible to access the values like so: (where your json is in the some_json variable.)
- debug:
msg: "{{ some_json.results | map(attribute='ID') | list }}"
results:
ok: [localhost] => {
"msg": [
"000041",
"000042"
]
}
If you want to do it with json_query/jmespath (As the question is also tagged with json_query and jmespath) then it would be like this:
- debug:
msg: "{{ some_json.results | json_query('[*].ID') | list }}"
ok: [localhost] => {
"msg": [
"000041",
"000042"
]
}
That being said, I do prefer the map method myself since it does not require any extra dependencies where as json_query requires jmespath to be installed.
What the syntax would be to pull the "members" value out of this JSON where the name value is "PROD_poolgroup".
I think it should be [?config.name == "PROD_poolgroup"].config.members
I've tried other variations without success also.
"all_members": [
{
"config": {
"_last_modified": "1594434546441212",
"cloud_ref": "https://192.168.86.20/api/cloud/cloud-5a7a41cb-156e-43f4-ad28-031b27dac813",
"implicit_priority_labels": false,
"members": [{
"pool_ref": "https://192.168.86.20/api/pool/pool-cb436bba-000a-4d72-8ff5-7d6cdf1ac2fa",
"ratio": 1
}],
"min_servers": 0,
"name": "PROD_poolgroup",
"tenant_ref": "https://192.168.86.20/api/tenant/admin",
"url": "https://192.168.86.20/api/poolgroup/poolgroup-e08933c0-d142-4787-9990-45f94dfc6b89",
"uuid": "poolgroup-e08933c0-d142-4787-9990-45f94dfc6b89"
},
"uuid": "poolgroup-e08933c0-d142-4787-9990-45f94dfc6b89"},
{
"config": {
"_last_modified": "1594404797173635",
"cloud_ref": "https://192.168.86.20/api/cloud/cloud-5a7a41cb-156e-43f4-ad28-031b27dac813",
"implicit_priority_labels": false,
"members": [{
"pool_ref": "https://192.168.86.20/api/pool/pool-f98ed65c-00b2-4638-83df-8b89df79deec",
"ratio": 1
}],
"min_servers": 0,
"name": "QA_poolgroup",
"tenant_ref": "https://192.168.86.20/api/tenant/admin",
"url": "https://192.168.86.20/api/poolgroup/poolgroup-0b19b515-9ae6-41ef-9111-00e61470e615",
"uuid": "poolgroup-0b19b515-9ae6-41ef-9111-00e61470e615"},
"uuid": "poolgroup-0b19b515-9ae6-41ef-9111-00e61470e615"
}
]
Use either single quote or backquote for using literal expression to compare value of name. Below are two working examples:
Using single quote:
- debug:
msg: "{{ all_members | json_query(query) | list }}"
vars:
query: "[?config.name == 'PROD_poolgroup'].config.members"
Using literal expression:
- debug:
msg: "{{ all_members | json_query(query) | list }}"
vars:
query: '[?config.name == `"PROD_poolgroup"`].config.members'
I am getting the below dictionary from calling python library called from Ansible.
{
"replication_detail": [
{
"name": "xxx.203.server:11111",
"self": true,
"state": 1,
"stateStr": "PRIMARY",
"syncSourceHost": "",
"syncingTo": ""
},
{
"name": "xxx.204.server:11111",
"state": 2,
"stateStr": "SECONDARY",
"syncSourceHost": "xxx.203,server:11111",
"syncingTo": "xxx.203,server:11111"
},
{
"name": "xxx.205,server:11111"
"state": 8,
"stateStr": "(not reachable/healthy)",
"syncSourceHost": "",
"syncingTo": ""
}
]
}
I wanted to have a filter which look into another element which is "StateStr" should be in ["PRIMARY","SECONDARY"] and return the "name"
I tried match or equalto but they all take only one value. Is there other any function which can look into multiple search values.
I am trying to get the data using map in single line rather than with_loop.
the code like
"select name from replication_detail where sateStr in (PRIMARY, SECONDARY)"
replication_detail| stateStr in (PRIMARY, SECONDARY)) | map(attribute="name"|list
You can use the selectattr filter to filter a list of dictionaries by an attribute. For example, if the data in your question is contained in a variable named data, then the following task:
- debug:
msg: "name: {{ item }}"
loop: "{{ data.replication_detail|selectattr('stateStr', 'match', 'SECONDARY|PRIMARY')|map(attribute='name')|list }}"
Would output:
TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => (item=xxx.203.server:11111) => {
"msg": "name: xxx.203.server:11111"
}
ok: [localhost] => (item=xxx.204.server:11111) => {
"msg": "name: xxx.204.server:11111"
}
Would output:
I have a yml list that is similar to the following:
name_ips:
rr: [
{
"name": "db1-137.com",
"ip": "1.1.1.1"
},
{
"name": "core1-137.com",
"ip": "2.2.2.2"
},
{
"name": "core0-139.com",
"ip": "3.3.3.3"
},
{
"name": "db0-147.com",
"ip": "4.4.4.4"
}
]
Using ansible I want to select the items in this list with name values matching the regex:
regexp: ".*137.com"
My end result should look similar to the following, which I want to be able to set using the set_fact module:
[
{
"name": "db1-137.com",
"ip": "1.1.1.1"
},
{
"name": "core1-137.com",
"ip": "2.2.2.2"
}
]
How can I achieve this sub-list select operation?
Update:
I found I can return a single value if I state the exact name:
- debug: msg="{{ name_ips | json_query(\"rr[?name=='core0-139.com']\") }}"`
Returns:
{
"name": "core0-139.com",
"ip": "3.3.3.3"
}
This is a start, but I would still like to use a regex for this search.