【问题标题】:JMESpath expression to filter object by property and return list of object names having this property setJMESpath 表达式按属性过滤对象并返回具有此属性集的对象名称列表
【发布时间】:2018-10-19 08:15:39
【问题描述】:

是否可以编写 JMESPath 表达式以返回设置了特定子属性值的对象名称列表?在下面的示例中,我想获取 fileexists.stat.exists 设置为 true 的所有主机名的列表。

我的目标是使用 Ansible hostvars 结构来获取存在特定文件的所有主机的列表。

{
"hostvars": {
    "oclab1n01.example.org": {
        "fileexists": {
            "changed": false, 
            "failed": false, 
            "stat": {
                "exists": false
            }
        }
    }, 
    "oclab1n02.example.org": {
        "fileexists": {
            "changed": false, 
            "failed": false, 
            "stat": {
                "exists": true
            }
        }
    }, 
    "oclab1n03.example.org": {
        "fileexists": {
            "changed": false, 
            "failed": false, 
            "stat": {
                "exists": true
            }
        }
    }
} }

在这个例子中,我想得到以下输出

["oclab1n02.example.org", "oclab1n03.example.org"]

【问题讨论】:

标签: ansible jmespath json-query


【解决方案1】:

简答 (TL;DR)

是的,这是可能的,但它非常麻烦,因为至少在使用 JMESpath 方面,对于这种通用查询,源数据集规范化很差。 p>

上下文

  • jmespath 查询语言
  • 查询深度嵌套对象的对象属性

问题

  • 如何使用过滤器表达式构造 jmespath 查询
  • 目标是过滤具有任意嵌套对象属性的对象

解决方案

  • 这可以用jmespath来完成,但是操作会繁琐
  • 一个有问题的问题:对于这种 jmespath 查询,源数据集规范化很差
  • 为了构造 jmespath 查询,我们必须假设在创建查询之前提前知道所有主对象键
  • 在这个具体的例子中,在构造 jmespath 查询之前,我们必须知道只有三个主机名 ...如果我们想要灵活地指定,这不是一个有利的情况任意数量的主机名

示例

以下(太大)jmespath 查询...

  [
    {
      "hostname": `oclab1n01.example.org`
      ,"fileexists_stat_exists":  @.hostvars."oclab1n01.example.org".fileexists.stat.exists
    }
    ,{
      "hostname": `oclab1n02.example.org`
      ,"fileexists_stat_exists":  @.hostvars."oclab1n02.example.org".fileexists.stat.exists
    }
    ,{
      "hostname": `oclab1n03.example.org`
      ,"fileexists_stat_exists":  @.hostvars."oclab1n02.example.org".fileexists.stat.exists
    }
  ]|[? @.fileexists_stat_exists == `true`]|[*].hostname

返回以下期望的结果

  [
    "oclab1n02.example.org",
    "oclab1n03.example.org"
  ]

陷阱

  • 此用例的一个主要缺陷是源数据集对于此类查询规范化不佳
  • 更扁平的数据结构更容易查询
  • 因此,如果可能的话,更好的方法是在对源数据集运行 jmespath 查询之前展平源数据集

具有不同原始数据集的替代示例

如果将原始数据组织为对象列表,而不是对象中的一组嵌套对象,则无需事先了解即可更轻松地搜索、排序和过滤列表涉及多少主机名条目。

{"hostvars": [
    {"hostname":"oclab1n01.example.org"
      ,"fileexists":        true
      ,"filechanged":       false
      ,"filefailed":        false
      ,"filestat_exists":   false
      ,"we_can_even_still_deeply_nest":{"however":
           {"im_only_doing":"it here","to":"prove a point"}
         }
     }
    ,{"hostname":"oclab1n02.example.org"
      ,"fileexists":        true
      ,"filechanged":       false
      ,"filefailed":        false
      ,"filestat_exists":   true
     }
    ,{"hostname":"oclab1n03.example.org"
      ,"fileexists":        true
      ,"filechanged":       false
      ,"filefailed":        false
      ,"filestat_exists":   true
     }
  ]
}

现在可以轻松查询上述重新归一化数据集

hostvars|[? @.filestat_exists == `true`]|[*].hostname

【讨论】:

  • 为什么你认为“key -> record”关系的标准化很差?在 salt 和 ansible 等配置管理软件中似乎非常惯用,但我确实发现大多数 jinja 过滤器,正如我今天了解到的那样,JMESPath 对 [val1, val2, val3] | map(f) -> [f(val1), f(val2), f(val3)] 非常有效,但对于 {key1: val1, key2: val2, key3: val3} | map(f) -> {key1: f(val1), key2: f(val2), key3: f(val3)} 则没有这么多。这是否从根本上难以实施?
  • @LLlAMnYP //为什么 [...] “key -> record” 关系的规范化很差// 仅针对此特定上下文,而不是一般情况。正如您所提到的,它是一种经常遇到的数据模式。这里的问题是避免与 JMespath 对抗,而不是使用它。 //这是否从根本上难以实现// 不是从根本上。问题是设计者是否选择使映射数据类型可迭代,就像列表类型一样。这只是一个设计决定。随意考虑类似于关系数据库,其中“行”(列表)比列“映射”更容易迭代。
猜你喜欢
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
  • 2012-08-11
  • 1970-01-01
  • 2013-03-08
  • 2015-06-21
相关资源
最近更新 更多