Ansible 用于按属性筛选对象并返回具有此属性集的对象名称列表的JMESpath表达式
是否可以编写JMESPath表达式以返回设置了特定子属性值的对象名称列表?在下面的示例中,我希望获得fileexists.stat.exists设置为true的所有主机名称的列表 我的目标是使用Ansible hostvars结构来获取存在特定文件的所有主机的列表Ansible 用于按属性筛选对象并返回具有此属性集的对象名称列表的JMESpath表达式,ansible,jmespath,json-query,Ansible,Jmespath,Json Query,是否可以编写JMESPath表达式以返回设置了特定子属性值的对象名称列表?在下面的示例中,我希望获得fileexists.stat.exists设置为true的所有主机名称的列表 我的目标是使用Ansible hostvars结构来获取存在特定文件的所有主机的列表 { "hostvars": { "oclab1n01.example.org": { "fileexists": { "changed": false, "fa
{
"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"]
简短回答(TL;DR)
是的,这是可能的,但它非常麻烦,因为至少在使用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//为什么[…]是一个“键->记录”关系规范化得很差//仅针对此特定上下文,而不是一般情况。正如您所提到的,这是一种经常遇到的数据模式。这里的问题是避免与JMespath对抗,而不是使用它//这从根本上说是很难实现的//不是从根本上。问题是设计器选择将映射数据类型设置为iterable,就像列表类型一样。这只是一个设计决策。请随意考虑类似于关系数据库的情况,其中“行”(列表)比“列映射”更容易迭代。