按属性过滤对象并使用 jmespath 中的键进行选择

Posted

技术标签:

【中文标题】按属性过滤对象并使用 jmespath 中的键进行选择【英文标题】:Filter object by property and select with key in jmespath 【发布时间】:2017-05-25 13:51:11 【问题描述】:

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

基于此示例数据:


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

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


  "a": 
    "feature": 
      "enabled": true,
    
  

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

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

*.feature.enabled*[feature.enabled] 只返回布尔值,没有任何上下文。

即使*[?feature.enabled==true] 可以工作,它也只是属性值的数组,但我还需要键(ac)。有没有办法在 jmespath 中实现这一点?

这都是 ansible playbook 的一部分,所以肯定有一种方法可以以不同的方式(Jinja2 模板或自定义插件)实现选择,但我想尝试 jmespath 并认为它应该能够做到这样一个任务。

【问题讨论】:

除了查询任何内容之外,您还想根据嵌套数据删除某些键。像this question for Perl 这样的东西。我也想知道你是否可以使用 JMESPath 来做到这一点。 另见: ***.com/a/55310594/42223 【参考方案1】:

你可以使用:

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

【讨论】:

这是做什么的?为什么你更喜欢这个而不是已经被社区验证的现有答案? 在 dict 上使用 * 的问题是您丢失了它的密钥,这是 OP 仍然具有原始密钥结构的要求之一。【参考方案2】:

简答 (TL;DR)

实际上,是的,这可以通过原生 jmespath 实现 问题是,针对源数据集的查询将非常麻烦,因为对于这种通用 jmespath 查询,源数据集规范化很差

示例

针对 OP 中的源数据的以下(太长的)jmespath 查询...

[
  
      "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`]

...产生以下结果

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

这与所需的输出相同或基本相似,但我们不得不弯曲大脑才能到达那里的事实表明我们正试图迫使一个方形钉穿过一个圆孔。

陷阱

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

这是因为它使用 对象键 作为***排序方法,而 sequentially-indexed-list 就足够了。

当您有一个可能包含任意数量的值的数据集时,几乎总是最好使用序列来进行***排序,而不是对象键。

如果你发现你可以在 jmespath 中做某事,但你必须修改你的 jmespath 查询,每当你向你的“任意(非固定)长度的条目集”添加另一个“条目”时,你是在对抗 Jmespath 而不是使用它。

每当您看到使用 Jmespath 似乎“无法完成”的查询时,您几乎可以肯定正在处理使用序列可能更合适的对象的数据结构。

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

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

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

另见

related *** post

【讨论】:

看起来很多在线 json 查看/格式化工具使用 jmespath 进行查询。你知道任何使用 jsonpath 的好工具吗? 例如看这张图:Sample comparison 所以,我想知道是否最好只使用一些编程语言而不是任何 json 查询语言。 JMES 看起来很丑。 你能帮我解决这个相关的问题吗***.com/questions/59206765/… ?【参考方案3】:

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

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

结果:

"msg": 
    "a": 
        "feature": 
            "enabled": true
        
    

【讨论】:

你能帮我解决这个相关的问题吗***.com/questions/59206765/… ?【参考方案4】:

抱歉,AFAIK 这在本机 JMESPath 中是不可能的。 在 to_entries 和 jq 等不同的工具中有为此目的定制的内置函数。 对于jmespath.py,因此对于 Ansible,有挂起 pull request 来实现键操作。

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

【讨论】:

谢谢,我正在关注拉取请求,目前我已经通过 jinja2 循环来选择匹配的字典项并将它们组合到一个新的字典中解决了这个问题。 看起来很多在线 json 查看/格式化工具使用 jmespath 进行查询。你知道任何使用 jsonpath 的好工具吗? 你能帮我解决这个相关的问题吗***.com/questions/59206765/… ?

以上是关于按属性过滤对象并使用 jmespath 中的键进行选择的主要内容,如果未能解决你的问题,请参考以下文章

使用Ansible中的json_query / jmespath过滤器进行多次搜索

按属性将对象数组与另一个对象的键进行比较

03-Httprunner-JMESPath提取返回结果

按 2 级深的键值关系对 NSArray 进行排序

Java 8 Stream 按键过滤对象列表。排除列表中的键并获取字符串

使用字典中的键对对象数组进行排序