Filter object by property and select with key in jmespath Filter object by property and select with key in jmespath json json

Filter object by property and select with key in jmespath


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

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

The result:

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


Sorry, but AFAIK this is impossible in native JMESPath.
There are custom built-in functions for this purpose in different tools like to_entries in jq.
For jmespath.py and thus for Ansible there is hanging pull request to implement keys manipulation.

Update: I've made a patched version of json_query filter.
See this answer for additional info.


Short answer (TL;DR)

  • Actually, yes, this is possible with nothing more than native jmespath
  • The problem is, queries against the source dataset will be extremely cumbersome, because the source dataset is poorly normalized for this kind of general-purpose jmespath query.

Example

The following (way-too-long) jmespath query against the source data in the 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`]

... produces the following result

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

Which is identical or substantially similar to the desired output, but the fact that we had to bend our brain to get there suggests we are trying to force a square peg through a round hole.

Pitfalls

The reason this jmespath query looks so long and cumbersome is that the source dataset itself is poorly normalized for a general purpose jmespath query.

That is because it uses object keys as a top-level collation method, when a sequentially-indexed-list would have sufficed.

Whenever you have a dataset that can potentially contain an arbitrary number of values it is almost always preferable to use a sequence for top-level collation, instead of object keys.

If you find you can do something in jmespath, but you have to modify your jmespath query whenever you add another "entry" to your "set of entries of arbitrary (non-fixed) length" you are fighting against Jmespath instead of working with it.

Whenever you see a query that seems "impossible to accomplish" with Jmespath, you are almost certainly dealing with a data structure that is using objects where sequences may have been more suitable.

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

Even object properties of arbitrarily deep nesting are just fine, so long as those object properties are not being used as a substitute for sequential enumeration.

Things only start to get uncomfortable when you find you are having to create sequences-of-objects in order to get around objects-of-objects ... which is entirely doable in jmespath, but it is going to be painful.

See also