# Issue with select(search,x) returning multiple results that is bugging the code

**URL:** <https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933>\
**Category:** Get Help\
**Tags:** ansible\
**Created:** [December 15, 2023, 6:46pm UTC](https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933 "2023-12-15T18:46:43Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![wolfdogg](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/wolfdogg/32/1809_2.png) [@wolfdogg](https://forum.ansible.com/u/wolfdogg)\
**Post date:** [December 15, 2023, 6:46pm UTC](https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933/1 "2023-12-15T18:46:43Z")

</div>

**I am. using `select('search')` to pull some results from a list of items that contains whitespace separated strings, and the search results are not returning the exact string im searching for, its returning the exact string, plus another string, and that other string is overriding the results which is buggy, or unexpected**

- I am parsing results from nomad node status.  
those results looks like this

```auto
  nomad_node_status_str: |-
    ID DC Name Class Drain Eligibility Status
    8a64d5e9 dc be7 BE false eligible ready
    7795cd1b dc be15 BE false ineligible ready
    8db38b87 dc be1 BE false eligible ready
    ba29bbb1 dc be2 BE false eligible ready
    a9635b5c dc be9 BE false eligible ready
    0d10c06a dc fe92 FE false eligible ready
    ca965927 dc fe46 FE false eligible ready

```

- I am then turning that into a list

```auto
  nomad_node_status_list:
  - ID DC Name Class Drain Eligibility Status
  - 8a64d5e9 dc be7 BE false eligible ready
  - 7795cd1b dc be15 BE false ineligible ready
  - 8db38b87 dc be1 BE false eligible ready
  - ba29bbb1 dc be2 BE false eligible ready
  - a9635b5c dc be9 BE false eligible ready
  - 0d10c06a dc fe92 FE false eligible ready
  - ca965927 dc fe46 FE false eligible ready

```

I then refine those results here (only because im trying to debug this, or i would have done it all in one action)

```auto
- name: restructure the output of nomad into a more usable object
  set_fact:
    # grab the id, and hastname which is the first item in the new list of text
    # make it a list of dicts
    node_host_map: "{{ node_host_map | default ([]) + [{_id:_text.0}] }}"
  # remove the first item in the list which is the headers
  loop: "{{ nomad_node_status_list[1:] }}"
  vars:
    # get the 3rd and beyond items in the whitespace separated string
    _text: "{{ item.split()[2:] }}"
    # get the ID which is the first item in the whitespace separated string
    _id: "{{ item.split() | first }}"
- debug:
    var: node_host_map

```

those results looks ike this now

```auto
  node_host_map:
  - 8a64d5e9: be7
  - 7795cd1b: be15
  - 8db38b87: be1
  - ba29bbb1: be2
  - a9635b5c: be9
  - 0d10c06a: fe92
  - ca965927: fe46

```

- i am then querying that variable using the select filter like this (in a loop that loops over the nomad ips, in the vars section (see \_node\_id)

```auto
 - name: set fact for all_node_host_map including all hostnames/ips including shutdown ones
  set_fact:
    line: "{{ line | default ([]) + _line }}"
    results: "{{ results | default ([]) + [{idx:[_nomad_host_ip_item, _hostvars_hostname, _nomad_hostname_ip_map_hostname, _node_id]} ] }}"
  loop: "{{ groups.nomad_instances_all }}"
  loop_control:
    loop_var: nomad_host_ip_item
    index_var: idx
  vars:
    _nomad_host_ip_item: "{{ nomad_host_ip_item }}"
    _hostvars_hostname: "{{ hostvars[nomad_host_ip_item]['ansible_hostname'] }}"
    _nomad_hostname_ip_map_hostname: "{{ nomad_hostname_ip_map[nomad_host_ip_item] }}"
    # for one element only, the one for be1, its returning two items, be1 and be15. since be15 is last, thats where the bug wasi
    # example for fe46 which looks like the rest, as expected, a single result for the _node_id that was filtered by select()
    #
    #- 8:
    # - 10.100.1.60
    # - be1
    # - be1
    # - - 7795cd1b: be15
    # - 8db38b87: be1
    #- 9:
    # - 10.100.1.46
    # - fe46
    # - fe46
    # - - ca965927: fe46
    _node_id: "{{ node_host_map | select('search',_hostvars_hostname) }}"

```

so sull results from \_node\_id is coming back like this

```auto
ok: [10.100.1.48] =>
  results:
  - 1:
    - 10.100.1.48
    - be15
    - be15
    - - 7795cd1b: be15
  - 3:
    - 10.100.1.93
    - be7
    - be7
    - - 8a64d5e9: be7
  - 5:
    - 10.100.1.92
    - fe92
    - fe92
    - - 0d10c06a: fe92
  - 6:
    - 10.100.1.25
    - be9
    - be9
    - - a9635b5c: be9
  - 7:
    - 10.100.1.91
    - be2
    - be2
    - - ba29bbb1: be2
  - 8:
    - 10.100.1.60
    - be1
    - be1
    - - 7795cd1b: be15
      - 8db38b87: be1
  - 9:
    - 10.100.1.46
    - fe46
    - fe46
    - - ca965927: fe46

```

Expected:  
When i select the \_node\_id line, I only expect one list string, that contains the node id. Notice in the be1 results i get be15 first. So when i select that line later in a more refined setup, i was only getting node\_id `7795cd1b` for be1, which erroneous.  
So i demonstrated it in a way that I can atleast know why the results were erroneus, and thats because the item for be1 is returning two result items. Why is that??

Do i simply need to add another filter? E.g. i Can add `| first` first but that could be disastrous, i would rather resolve how to select/search properly, or maybe use map or match instead, if someone can show me how to better extract the correct linle from the `nomad_node_status_list` or `node_host_map`

Is this a bug?

- ansible -v 2.14.2  
python 3.11.2

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [December 15, 2023, 6:54pm UTC](https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933/2 "2023-12-15T18:54:05Z")

</div>

Sorry this doesn’t directly answer you question but have you considered using the [community.general.read\_csv module](https://docs.ansible.com/ansible/latest/collections/community/general/read_csv_module.html) or the [jc csv parser](https://kellyjonbrazil.github.io/jc/docs/parsers/csv) via the [community.general.jc filter](https://docs.ansible.com/ansible/latest/collections/community/general/jc_filter.html) to parse the data to potentially make it easier to extract the exact bits needed?

Also rather than `select('search',_hostvars_hostname)` would `select('regex',_hostvars_hostname)` return the expected result?

---

<div class="post-metadata">

**Author:** ![flowerysong](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/flowerysong/32/2305_2.png) [@flowerysong](https://forum.ansible.com/u/flowerysong)\
**Post date:** [December 15, 2023, 7:12pm UTC](https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933/3 "2023-12-15T19:12:36Z")

</div>

This is not a bug. `search` matches using regex, and the regex `be1` matches both `be1` and `be15`. You may be able to make it work by adding an anchor or otherwise making the regex more exact, but personally I would just construct an actual map in the first place:

```yaml
- hosts: localhost
  vars:
    nomad_node_status_str: |-
      ID DC Name Class Drain Eligibility Status
      8a64d5e9 dc be7 BE false eligible ready
      7795cd1b dc be15 BE false ineligible ready
      8db38b87 dc be1 BE false eligible ready
      ba29bbb1 dc be2 BE false eligible ready
      a9635b5c dc be9 BE false eligible ready
      0d10c06a dc fe92 FE false eligible ready
      ca965927 dc fe46 FE false eligible ready
  tasks:
    - set_fact:
        node_host_map: "{{ node_host_map | default({}) | combine({_text.0: node_host_map[_text.0] | default([]) | union([_id])}) }}"
      loop: "{{ (nomad_node_status_str.splitlines())[1:] }}"
      vars:
        _text: "{{ item.split()[2:] }}"
        _id: "{{ item.split() | first }}"

    - debug:
        msg: "{{ node_host_map }}"

```

Output:

```auto
TASK [set_fact] ****************************************************************
ok: [localhost] => (item=8a64d5e9 dc be7 BE false eligible ready)
ok: [localhost] => (item=7795cd1b dc be15 BE false ineligible ready)
ok: [localhost] => (item=8db38b87 dc be1 BE false eligible ready)
ok: [localhost] => (item=ba29bbb1 dc be2 BE false eligible ready)
ok: [localhost] => (item=a9635b5c dc be9 BE false eligible ready)
ok: [localhost] => (item=0d10c06a dc fe92 FE false eligible ready)
ok: [localhost] => (item=ca965927 dc fe46 FE false eligible ready)

TASK [debug] *******************************************************************
ok: [localhost] =>
    msg:
        be1:
        - 8db38b87
        be15:
        - 7795cd1b
        be2:
        - ba29bbb1
        be7:
        - 8a64d5e9
        be9:
        - a9635b5c
        fe46:
        - ca965927
        fe92:
        - 0d10c06a

```

---

<div class="post-metadata">

**Author:** ![wolfdogg](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/wolfdogg/32/1809_2.png) [@wolfdogg](https://forum.ansible.com/u/wolfdogg)\
**Post date:** [December 16, 2023, 2:37am UTC](https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933/4 "2023-12-16T02:37:15Z")

</div>

Thanks!!

I went with the latter option

```auto
    - set_fact:
        node_host_map: "{{ node_host_map | default({}) | combine({_text.0: node_host_map[_text.0] | default([]) | union([_id])}) }}"
      loop: "{{ (nomad_node_status_str.splitlines())[1:] }}"
      vars:
        _text: "{{ item.split()[2:] }}"
        _id: "{{ item.split() | first }}"

```

I noticed that in place of union this also worked

```auto
node_host_map: "{{ node_host_map | default({}) | combine({_text.0: node_host_map[_text.0] | default([]) + [_id] } ) }}"

```

Is there an advantage to using union which could be a bit more of a learning curve for those that need to manage the code later? I was thinking maybe there was some functionality that benefitted such as when the \_id is empty or something?..

Also, whats the definition of an

> actual map

-Brian

---

<div class="post-metadata">

**Author:** ![flowerysong](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/flowerysong/32/2305_2.png) [@flowerysong](https://forum.ansible.com/u/flowerysong)\
**Post date:** [December 16, 2023, 3:04am UTC](https://forum.ansible.com/t/issue-with-select-search-x-returning-multiple-results-that-is-bugging-the-code/2933/5 "2023-12-16T03:04:46Z")

</div>

> [@wolfdogg](#):
>
> Is there an advantage to using union which could be a bit more of a learning curve for those that need to manage the code later? I was thinking maybe there was some functionality that benefitted such as when the \_id is empty or something?..

I basically always use `union` because it deduplicates items and I find it easier to read. In this situation it probably has no practical difference.

> [@wolfdogg](#):
>
> Also, whats the definition of an
> 
> > actual map

Map is another term for a dictionary/hash, because it maps values to keys (see [Built-in Types — Python 3.12.1 documentation](https://docs.python.org/3/library/stdtypes.html#typesmapping.)) Despite the name of the variable the structure you were creating was a list, which you then had to iterate over to find the item corresponding to the key you wanted.
