Filter object by property and select using key in jmespath

I am trying to filter the properties of an object in jmespath based on the value of a subtask and I want to include only those properties where a specific value is set for the subtask.

Based on the example data:

{ "a": { "feature": { "enabled": true, } }, "b": { }, "c": { "feature": { "enabled": false } } } 

I would like to get an object with all the properties in which the function is enabled.

 { "a": { "feature": { "enabled": true, } } } 

I decided that I could use this jmespath request to filter objects where property. enabled property. enabled set to true. Unfortunateley does not seem to work and instead returns an empty array.

 *[?feature.enabled==`true`] 

*.feature.enabled or *[feature.enabled] returns only boolean values ​​without any context.

Even if *[?feature.enabled== true ] works, it will just be an array of property values, but I need the keys ( a and c ). Is there a way to do this in jmespath?

This is all part of an unoccupied play, so of course there is a way to make a choice differently (Jinja2 templates or a custom plugin), but I wanted to try jmespath and reason that it should be capable of such a task.

+13
source share
3 answers

Sorry, but AFAIK is not possible in the native JMESPath.
For this purpose, there are special built-in functions in various tools, such as to_entries in jq .
For jmespath.py and therefore for Ansible, there is a hang request pull to implement key manipulation.

Update: I made a fixed version of the json_query filter.
See more details.

+6
source

With the dict2items filter dict2items in Ansible 2.5 and later, you can do this with:

 - debug: msg: "{{ dict(my_data | dict2items | json_query('[?value.feature.enabled].[key, value]')) }}" 

Result:

 "msg": { "a": { "feature": { "enabled": true } } } 
+4
source

Short answer (TL; DR)

  • In fact, yes, this is only possible with native jmespath
  • The problem is that queries to the original dataset will be extremely cumbersome because the original dataset is poorly normalized for this kind of general jmespath query.

example

The following (too long) jmespath query for source data in OP ...

 [ { "item_key": 'a' ,"feature_enabled": @.a.feature.enabled ,source_object: @.a } ,{ "item_key": 'b' ,"feature_enabled": @.b.feature.enabled ,source_object: @.b } ,{ "item_key": 'c' ,"feature_enabled": @.c.feature.enabled ,source_object: @.c } ]|[? feature_enabled == 'true'] 

... gives the following result

 [ { "item_key": "a", "feature_enabled": true, "source_object": { "feature": { "enabled": true } } } ] 

This is identical or substantially similar to the desired result, but the fact that we had to bend our brains to get to it suggests that we are trying to push a square peg through a round hole.

Traps

The reason this jmespath query looks so long and cumbersome is because the original dataset itself is poorly normalized for the general jmespath query.

This is because it uses object keys as a top-level matching method when a sequential indexed list would suffice.

When you have a data set that can contain an arbitrary number of values, it is almost always preferable to use a sequence to match the top level instead of the keys of the object.

If you find that you can do something in jmespath, but you need to modify the jmespath request whenever you add another “record” to the “record set of arbitrary (not fixed) length”, you are fighting with Jmespath, not working with him

Whenever you see a query that seems “impossible to execute” with Jmespath, you are almost certainly dealing with a data structure using objects where sequences may be more appropriate.

Object keys usually mean a fixed number of properties that jmespath can handle just fine.

Even the properties of an object of arbitrarily deep nesting are simply good if these properties of the object are not used as a substitute for sequential enumeration.

Things start to become uncomfortable when you discover that you need to create sequences of objects to go around object objects ... which is quite doable in jmespath, but it will be painful.

see also

0
source

Source: https://habr.com/ru/post/1013958/


All Articles