Выражение JMESPath для выравнивания массива объектов, каждый из которых содержит вложенные массивы объектов - PullRequest
0 голосов
/ 12 января 2019

У меня есть JSON, содержащий массив баз данных, каждая база данных имеет массив пользователей, например,

{"databases": [
  {"db": "db_a", "users": [{"name": "alice"}, {"name": "alex"}]},
  {"db": "db_b", "users": [{"name": "bob"}, {"name": "brienne"}]}
]}

Я хотел бы создать плоский массив баз данных и пользователей, т.е.

[
  {"db": "db_a", "name": "alice"},
  {"db": "db_a", "name": "alex"},
  {"db": "db_b", "name": "bob"},
  {"db": "db_b", "name": "brienne"}
]

В терминах SQL это будет декартово соединение или декартово произведение, но я не уверен в правильности термина в древовидной структуре. Самое близкое, что у меня есть, это

databases[].users[]

, который производит

[{"name": "alice"}, {"name": "alex"}, {"name": "bob"}, {"name": "brienne"}]

и

databases[].{db: db, name: users[].name}

, который производит

[
  {"db": "db_a", "name": ["alice", "alex"]},
  {"db": "db_b", "name": ["bob", "brienne"]}
]

Приложение: Я рад принять ответ «Вы не можете сделать это с JMESPath, вот почему ...». Комментарий HN `` намекает на это

не может ссылаться на родителей при выполнении итерации. Зачем? Все опции для итерации, [*] и map, все используют итеративный элемент в качестве контекста для любого выражения. Там нет возможности получить какие-либо другие значения в

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Вы не можете сделать это с просто JMESPath, потому что выражения JMESPath могут ссылаться только на одну область видимости. Нет никакого способа достичь внешней области (объектов базы данных), когда текущая область является объектом пользователя. JEP 11 разрешит доступ к другим областям, но он не был принят через несколько лет.

На Ansible это можно сделать с другими фильтрами (х / т Владимир), и немного уродства

databases_users: "{{ 
    databases | subelements('users')
              | to_json | from_json
              | json_query('[*].{db: [0].db, name: [1].name}')
}}"

Объяснение

Напоминаем, что наша отправная точка

[ {"db": "db_a", "users": [{"name": "alice"}, {"name": "alex"}]},
  ...]

фильтр subelements преобразует это в список пар кортежей Python

[ ({"db": "db_a", "users": [{"name": "alice"}, {"name": "alex"}]},
   {"name": "alice"}),
  ...]

to_json и from_json преобразовывают пары кортежей в списки (JMESPath для Python игнорирует кортежи)

[ [{"db": "db_a", "users": [{"name": "alice"}, {"name": "alex"}]},
   {"name": "alice"}],
  ...]

json_query выбирает нужные значения db и user

[ {"db": "db_a", "name": "alice"},
  ...]
0 голосов
/ 12 января 2019

Опцией будет подэлементы цикла

  tasks:
    - set_fact:
        my_db: "{{ my_db + [ item.0|combine(item.1) ] }}"
      loop: "{{ lookup('subelements',databases,'users') }}"
...