Filter object by property and select with key in jmespath

本小妞迷上赌 提交于 2019-11-28 09:07:39

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.

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
        }
    }
}

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!