#Is there a way to simplify this template for searching through nested lists?

1 messages · Page 1 of 1 (latest)

quick willow
#

I have a variable (in an automation) that is of the form:

users:
  - full_name: Some Name
    user_status: ACTIVE
    ulp_id: XXXX-XXXX
    keys:
      - key_type: nfc
        nfc_id: ABC123

The event data that triggers the automation has the nfc_id, and I want to match that to the full_name of the user containing that nfc_id. I currently am doing that with this code:

- variables:
      name: >
        {% set ns = namespace(name_ = "Unknown") %}
        {% for user in keyring.users %}
          {% for key in user['keys'] %}
            {% 
              if key.key_type == "nfc" and 
              key.nfc_id == trigger.event.data.new_state.attributes.nfc_id
            %}
              {% set ns.name_ = user.full_name %}
            {% endif %}
          {% endfor %}
        {% endfor %}
        {{ ns.name_ }}

Is there a cleaner way of achieving my goal here?

#

I guess a message can only have 1 code block in it.

quick furnace
#

You didn't open the second code block with back ticks, you used single quotes instead

zenith bridge
#

Need a line break after the 3 opening backticks too. Or maybe at least a space, I forget

winter glacierBOT
#

To format your text as code, enter three backticks on the first line, press Enter for a new line, paste your code, press Enter again for another new line, and lastly three more backticks.
```yaml
example: here
```
Don't forget you can edit your post rather than repeatedly posting the same thing.

quick willow
#

they are back ticks. adding the line break caused the - to turn into the dot. Also, in the editor, the three back ticks change the formatting to look like it's going to be a quote block, but when saved it displays as you see it

zenith bridge
#

Does your code work and you are just wondering if there is a more efficient method?

quick willow
#

yeah. it does work, but it feels like a mess having nested loops and having to deal with the namespace issue

zenith bridge
quick willow
#

I was hoping there is some tidy way of doing it using the pipes

#

they do. I think it's just a strange discord bug. I guess I'll complain to my friend who's a staff engineer there

zenith bridge
#

I'm going to chew on this for a minute. If TheFes was still here he would probably spit out the answer immediately

quick willow
#

I will also say that getting my code working in the first place was pretty annoying until I figured out the problem was accessing the "keys" list using the . notation

zenith bridge
#

yeah you can do .dot notation or ['bracket'] notation

quick willow
#

I mean, I was doing {% for key in user.keys %} and that results in: "TypeError: 'builtin_function_or_method' object is not iterable"

zenith bridge
#

ah, yeah when there's an existing function that conflicts with the name of the key, you have to use bracket notation

zenith bridge
#

This is the template you need; you should be able to integrate it into your code

{{ users | selectattr('keys.key_type', 'eq', 'nfc') | selectattr('keys.nfc_id', 'eq', 'ABC123') | map(attribute='full_name') | first }}
shut sorrel
#

actually, no

#

I don't think this can be done without a forloop

#

keys.key_type won't exist

#

This is likely the best you can do

#
        {% set ns = namespace(name="Unknown") %}
        {% for user in keyring.users if user.keys | selectattr('key_type', 'eq', 'nfc') | selectattr('nfc_id', 'eq', trigger.event.data.new_state.attributes.nfcid) | list | first | default %}
          {% set ns.name = user.fullname %}
        {% endfor %}
        {{ ns.name }}
zenith bridge
# shut sorrel keys.key_type won't exist

I updated with keyring.users I think it still works, unless I did something wrong setting up variables:

{% set keyring = {'users':[{'full_name': 'Some Name', 'user_status': 'ACTIVE', 'ulp_id': 'XXXX-XXXX', 'keys': {'key_type': 'nfc', 'nfc_id': 'ABC123'}}, {'full_name': 'Some Name2', 'user_status': 'INACTIVE', 'ulp_id': 'YYYY-YYYYY', 'keys': {'key_type': 'nfc', 'nfc_id': 'DEF456'}} ] } %}

{% set trigger = {'event': {'data': {'new_state': {'attributes': {'nfc_id': 'DEF456'} }}}} %}

{{ keyring.users
 | selectattr('keys.key_type', 'eq', 'nfc')
 | selectattr('keys.nfc_id', 'eq', trigger.event.data.new_state.attributes.nfc_id)
 | map(attribute='full_name')
 | first }}
shut sorrel
zenith bridge
#

shit you are right

shut sorrel
#
{% set keyring = {'users':[{'full_name': 'Some Name', 'user_status': 'ACTIVE', 'ulp_id': 'XXXX-XXXX', 'keys': [{'key_type': 'nfc', 'nfc_id': 'ABC123'}]}, {'full_name': 'Some Name2', 'user_status': 'INACTIVE', 'ulp_id': 'YYYY-YYYYY', 'keys': [{'key_type': 'nfc', 'nfc_id': 'DEF456'}]} ] } %}
#

whats a pain is that he wants the username

#

if we were able to merge the lists, then we wouldn't need namespace

zenith bridge
#

merge the list of keys from each user? I'm not following

shut sorrel
#

you can sum lists together

#

e.g. {{ keyring.users | map(attribute='keys') | sum(start=[]) | ...}}

#

but that doesn't help because you lose the reference to users

#

which is what OP wants

zenith bridge
#

can get down to this, but I think a loop is still needed to do anything with it
zip(keyring.users | map(attribute='full_name'), keyring.users | map(attribute='keys')) | flatten(1)