2

I'd like to filter out entries from a nested list depending on a presence of a key. Given the following dictionary:

hostvars:
  host1:
    backups:
      - src: somesource
        target: sometarget
      - src: anothersource
  host2:
    backups:
      - src: somesource for host2
        target: fancy target
  host3:
    backups:
      - src: yet another src
      - src: and another one

I'd like to filter out all elements of the backups lists when the target key is not present.

The closest I've come is:

- set_fact:
    data: "{{ hostvars | dict2items | json_query(query) }}"
  vars:
    query: "[?value.backups[?target]]"

which results in

hostvars:
  host1:
    backups:
      - src: somesource
        target: sometarget
      - src: anothersource
  host2:
    backups:
      - src: somesource for host2
        target: fancy target

So I've successfully filtered out host3 which does not have an element containing the target key in the backups list.
However, I'd also like to remove the second element from the backups list of host1 (which also does not contain the target key).

Any pointers are greatly appreciated.

2 Answers 2

1

For example

    - set_fact:
        data: "{{ hostvars|
                  dict2items|
                  json_query(_query)|
                  selectattr('value')|
                  items2dict }}"
      vars:
        _query: '[].{key: key, value: value.backups[?target]}'
      run_once: true

gives

  data:
    host1:
    - src: somesource
      target: sometarget
    host2:
    - src: somesource for host2
      target: fancy target

The next option is adding the default attribute target: None if missing, e.g.

    - set_fact:
        backups: "{{ [{'target': None}]|product(backups)|map('combine') }}"
    - debug:
        var: backups

gives

TASK [debug] ****************************************************
ok: [host1] => 
  backups:
  - src: somesource
    target: sometarget
  - src: anothersource
    target: null
ok: [host2] => 
  backups:
  - src: somesource for host2
    target: fancy target
ok: [host3] => 
  backups:
  - src: yet another src
    target: null
  - src: and another one
    target: null

Then, select 'not null' targets

    - set_fact:
        data: "{{ hostvars|
                  json_query('*.backups')|
                  map('selectattr', 'target')|
                  flatten }}"
      run_once: true
    - debug:
        var: data
      run_once: true

gives

TASK [debug] ****************************************************
ok: [host1] => 
  data:
  - src: somesource
    target: sometarget
  - src: somesource for host2
    target: fancy target

To identify the host add this attribute to the lists too, .e.g

    - set_fact:
        backups: "{{ [{'target': None, 'host': inventory_hostname}]|
                     product(backups)|map('combine') }}"

gives the result

TASK [debug] ****************************************************
ok: [host1] => 
  data:
  - host: host1
    src: somesource
    target: sometarget
  - host: host2
    src: somesource for host2
    target: fancy target
Sign up to request clarification or add additional context in comments.

Comments

0

In a pure JMESPath way, you could recreate the value property doing a merge of the actual value with a filtered backups property with the query:

[].{
  key: key, 
  value: merge(value, {backups: value.backups[?target]})
} | [?value.backups]

So, given the task:

- debug:
    var: hostvars | dict2items | json_query(query) | items2dict
  vars:
    query: >-
      [].{
        key: key,
        value: merge(value, {backups: value.backups[?target]})
      } | [?value.backups]

This yields:

hostvars | dict2items | json_query(query) | items2dict:
  host1:
    backups:
    - src: somesource
      target: sometarget
  host2:
    backups:
    - src: somesource for host2
      target: fancy target

Comments

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.