使用 jmespath 中的键按 属性 和 select 过滤对象

Filter object by property and select with key in jmespath

我正在尝试根据 sub属性 的值过滤 jmespath 中对象的属性,并且只想包含设置了 sub属性 的那些属性到特定值。

基于此示例数据:

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

我想获得一个对象,该对象具有启用该功能的所有属性。

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

我想我可以使用这个 jmespath 查询来过滤 property. enabled 设置为 true 的对象。不幸的是,它似乎不起作用,而是 returns 一个空数组。

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

*.feature.enabled*[feature.enabled] return 只是没有任何上下文的布尔值。

即使 *[?feature.enabled==true] 可行,它也只是 属性 值的数组,但我需要键(ac) 还有。有什么办法可以在 jmespath 中做到这一点吗?

这是 ansible 剧本的全部内容,因此肯定会有一种方法以不同的方式(Jinja2 模板或自定义插件)实现选择,但我想尝试 jmespath 并且会推断,它应该有能力这样的任务。

抱歉,据我所知,这在本机 JMESPath 中是不可能的。
在不同的工具中有用于此目的的自定义内置函数,例如 to_entries in jq.
对于 jmespath.py,因此对于 Ansible,有挂起 pull request 来实现键操作。

更新: 我制作了 json_query 过滤器的补丁版本。
有关更多信息,请参阅 答案。

在 Ansible 2.5 及更高版本中使用 dict2items 过滤器,您可以使用:

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

结果:

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

简答(长话短说)

  • 实际上,是的,这只需要原生的 jmespath
  • 问题是,对源数据集的查询将非常麻烦,因为对于这种通用的 jmespath 查询,源数据集标准化程度很低

例子

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.

陷阱

此 jmespath 查询看起来如此冗长和繁琐的原因是 源数据集 本身对于通用 jmespath 查询的标准化很差。

这是因为它使用 object keys 作为顶级排序方法,而 sequentially-indexed-list 就足够了.

只要您的数据集可能包含任意数量的值,几乎总是最好使用序列进行顶级排序,而不是对象键。

如果您发现可以在 jmespath 中做一些事情,但是每当您向 "set of entries of arbitrary (non-fixed) length" 添加另一个 "entry" 时都必须修改您的 jmespath 查询,那么您就是在对抗 Jmespath 而不是使用它。

每当您看到一个似乎 "impossible to accomplish" 带有 Jmespath 的查询时,您几乎可以肯定是在处理一个使用序列可能更合适的对象的数据结构。

对象键通常意味着固定数量的属性,jmespath 可以处理得很好。

即使是任意深度嵌套的对象属性也很好,只要这些对象属性不被用作顺序枚举的替代品。

当您发现必须创建对象序列以绕过对象对象时,事情才开始变得不舒服......这在 jmespath 中是完全可行的,但它将是痛苦。

另见

  • related Whosebug post

您可以使用:

<json_data>|[*]|[? @.feature.enabled]