I have a list of dict mydicts=[{name: foo, data: 1}, {name: foo1, data: 3}, {name: bar, data: 2}]
and a list of names names=[foo, foo1, mars, jonh]
I want to create the list of dict only contains names in the list. I know if I want to select single dict I can do jq="[?(name=='foo')]"
then mydicts | json_query(jq)
. However I cannot make the contains version work so far. I need something like [?(contains(names, name))]
. Can any one show me an example about how to do this?
It seems json_query correctly get the value name with contains in jq2, but it think it is a variable instead of string. I just found out there is a bug in ansible we need this | to_json | from_json
to handle it.
In jq3, it seems it never get the value names
I guess I need to wrap both mydicts and names into a dict and pass to jsn_query
- hosts: localhost
gather_facts: False
vars:
mydicts:
- name: foo
data: 1
- name: bar
data: 2
names:
- foo
- foo1
- mars
- jonh
jq1: "[?(name == 'foo')]"
jq2: "[?(contains(name, 'f'))]"
jq3: "[?(contains(names, name))]"
tasks:
- debug:
var: json
- name: JMEPath test equal
debug:
msg: "{{mydicts | json_query(jq1)}}"
- name: JMEPath test str contain str does not work
debug:
msg: "{{mydicts | json_query(jq2)}}"
- name: JMEPath test another list contain str
debug:
msg: "{{mydicts | json_query(jq3)}}"
ignore_errors: yes
TASK [JMEPath test equal] ************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
{
"data": 1,
"name": "foo"
}
]
}
TASK [JMEPath test str contain str] **************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "JMESPathError in json_query filter plugin:\nIn function contains(), invalid type for value: foo, expected one of: ['array', 'string'], received: \"unknown\""}
...ignoring
TASK [JMEPath test another list contain str] *****************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "JMESPathError in json_query filter plugin:\nIn function contains(), invalid type for value: None, expected one of: ['array', 'string'], received: \"null\""}
...ignoring
For this simple example, there is a work around: using jinja filter "{{mydicts | selectattr('name', 'in', names) | list}}"
. But I still need the json_query functionality for deep nested keys.
JMESPath does not have visibility into the jinja2 variables in the same way that the jinja2 filters do, which is why the reference to names
doesn't do what you are expecting: JMESPath thinks that is a field on the current-node named names
, rather than a reference to that jinja2 variable
AFAIK you can either construct an artificial input structure just to make both of those pieces of data available to JMESPath (akin to {"names": [...], "mydicts": ...}
or you can inline the names
list into the JMESPath query:
- debug:
msg: '{{ mydicts | json_query(jq) }}'
vars:
jq: '[? contains(`{{ names | to_json }}`, name) ]'