在ansible中使用json_query组合属性值

Combine attribute value using json_query in ansible

我想使用 ansible 中的 json_query 将两个属性组合成由定界符分隔的单个字符串
示例数据

{
  "locations": [
    {"name": "Seattle", "state": "WA"},
    {"name": "New York", "state": "NY"},
    {"name": "Bellevue", "state": "WA"},
    {"name": "Olympia", "state": "WA"}
  ]
}

如上面的数据集所示,我正在尝试过滤状态“WA”并且执行的输出是:

[
    "Seattle-WA",
    "Bellevue-WA",
    "Olympia-WA"
]

我目前尝试过的:

    - debug:
        msg: "{{ chart_list.HELM_CHARTS | json_query(\"[?state == 'WA'].{name:name,state:state}\") }}"
Output:
[
  {
    "name": "Seattle",
    "state": "WA"
  },
  {
    "name": "Bellevue",
    "state": "WA"
  },
  {
    "name": "Olympia",
    "state": "WA"
  }
]

更新: 我能够通过反复试验的方法获得预期的结果,这些是我的发现:

[?state == 'WA'].[join('-',[name,state])][]
Output:
[
  "Seattle-WA",
  "Bellevue-WA",
  "Olympia-WA"
]

此外,如果您提供的输入是 unicode 格式,我建议您添加 to_json | from_json 表达式,如下所述:

        selected_cities: "{{ test.locations| to_json | from_json | json_query(\"[?state == 'WA'].[join('-',[name,state])][]\") }}"

使用上面的表达式将消除在使用值时或在任何情况下的 unicode 错误。 查看 JMESPath 站点以获取有关 json_query 的更多详细信息,这对解决问题很有帮助。

例如

    - debug:
        msg: "{{ locations|
                 json_query('[?state == `WA`].[name,state]')|
                 map('join', '-')|list }}"

给予

  msg:
  - Seattle-WA
  - Bellevue-WA
  - Olympia-WA

同样的结果给出了下面仅使用 Jinja2 过滤器的任务

    - debug:
        msg: "{{ _names|zip(_states)|map('join', '-')|list }}"
      vars:
        _locations: "{{ locations|selectattr('state', 'eq', 'WA')|list }}"
        _names: "{{ _locations|map(attribute='name')|list }}"
        _states: "{{ _locations|map(attribute='state')|list }}"

json_query 问题(已在 2.10 及更高版本中修复)

有 JMESPath join。遗憾

    - debug:
        msg: "{{ locations|
                 json_query('[].join(`-`, [name,state])') }}"

失败

msg: |- JMESPathError in json_query filter plugin: In function join(), invalid type for value: Seattle, expected one of: ['array-string'], received: "AnsibleUnicode"

to_json|from_json 解决方法

引用自json_query: Add examples for starts_with and contains #72821

data structure returned from register variables needs to be parsed using to_json | from_json in order to get a correct result. Fixes: ansible-collections/community.general#320

    - debug:
        msg: "{{ locations|to_json|from_json|
                 json_query('[].join(`-`, [name,state])') }}"

给予

  msg:
  - Seattle-WA
  - New York-NY
  - Bellevue-WA
  - Olympia-WA

只是为了采用纯 JMESPath 方法,因为您的试错解决方案仍然具有不必要的额外复杂层。

当你在做的时候

[?state == 'WA'].[join('-', [name, state])][]

您正在创建一个数组 [join('-', [name, state])] 然后无缘无故地展开它 []

您可以使用更简短的方法找到解决方案:

[?state == `WA`].join(`-`, [name, state])

另请注意,您可以使用以下方法克服 JMESPath 查询的引号中的引号(单引号或双引号)复杂性:

  1. YAML 多行字符串:How do I break a string in YAML over multiple lines?

  2. JMESPath 查询中的反引号,如文档中所述:

    In the example above, quoting literals using backticks avoids escaping quotes and maintains readability.

    来源:https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#selecting-json-data-json-queries


所以你最终得到(如果你使用的是 < 2.10 的 Ansible 版本,请参阅下面的注释):

- debug:
    msg: >-
      {{ test.locations 
           | json_query('[?state == `WA`].join(`-`, [name, state])') }}

请注意:如 @Vladimir Botka on the versions prior to 2.10, you will be affected by this issue: https://github.com/ansible/ansible/issues/27299#issuecomment-331068246 所述,强制您在列表中添加 | to_json | from_json 过滤器。


鉴于剧本:

- hosts: all
  gather_facts: yes

  tasks:
    - debug:
        msg: >-
          {{ test.locations 
              | json_query('[?state == `WA`].join(`-`, [name, state])') 
          }}
      vars:
        test:
          locations:
            - name: Seattle
              state: WA
            - name: New York
              state: NY
            - name: Bellevue
              state: WA
            - name: Olympia
              state: WA

这产生:

[
    "Seattle-WA",
    "Bellevue-WA",
    "Olympia-WA"
]