Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get value of nested attribute by filtering list on other attribute with Python Glom

Tags:

python

json

glom

I have a data object like this:

data = {
    'props': {
        'items': [
            {'name': 'a', 'content': 'plain'},
            {'name': 'b', 'content': {'id': 'x'}},
            {'name': 'c', 'content': {'id': 'y'}},
        ]
    }
}

Using glom, I want to get x which is the value of id for the item with name equal to b.

So far, I have this:

from glom import glom
from glom import SKIP


glom(data, ('props.items', [lambda i: i if i['name']=='b' else SKIP]))

Which returns:

[{'name': 'b', 'content': {'id': 'x'}}]

I can't figure out what spec (in glom parlance) to use to extract the only element in the returned list and then the value of id.

I could call glom twice:

glom(glom(data, ('props.items', [lambda i: i if i['name']=='b' else SKIP]))[0], 'content.id')

But I figured there should be a way of doing it in one call. Any ideas on how to achieve this?

like image 943
Pablo Avatar asked Jan 07 '19 16:01

Pablo


1 Answers

You were very close! The nice thing about glom chaining (which you're doing with that tuple there), is that you basically never need to call glom twice. You can just chain straight through:

>>> glom(data, ('props.items', [lambda i: i if i['name']=='b' else SKIP], '0.content.id'))
'x'

All I did was add a third element '0.content.id', which gets the first item, then the content key, then the id key.

For a slightly more glom-oriented way, you can rewrite that lambda to the following:

>>> glom(data, ('props.items', [Check('name', equal_to='b', default=SKIP)], '0.content.id'))
'x'

It does the same thing and is actually slightly longer, but might read a little better. Combine this with another Check for validation, and you can even prevent the final lookup step if no object with the name is found:

>>> glom(data, ('props.items', [Check('name', equal_to='z', default=SKIP)], Check(default=STOP), '0.content.id'))
[]

Don't forget to import Check and STOP if you go that route. Also, if the spec is getting long, you can give it a nice descriptive variable name :) Thanks for the great question!

like image 176
Mahmoud Hashemi Avatar answered Oct 02 '22 14:10

Mahmoud Hashemi