JMESPath表达式可展平对象数组,每个对象均带有嵌套的对象数组

时间:2019-01-12 14:10:23

标签: json ansible jmespath

我有一个包含数据库数组的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 Comment``暗示了这一点

  

进行迭代时无法引用父母。为什么?用于迭代的所有选项,[*]和map都将迭代项用作任何表达式的上下文。没有机会获得其他任何值

2 个答案:

答案 0 :(得分:1)

可以选择loop subelements

In [1]: L = np.array([[0,1,2,3,4], [5,6,7,8,9]])
   ...: L[[0,1], 0] = L[[1,0], 0]
   ...: L

Out[1]: 
array([[5, 1, 2, 3, 4],
       [0, 6, 7, 8, 9]])

答案 1 :(得分:0)

您不能使用 just JMESPath做到这一点,因为JMESPath表达式只能引用单个作用域。当前范围是用户对象时,无法到达外部范围(数据库对象)。 JEP 11将允许访问其他范围,但是几年后才被接受。

在Ansible上,可以使用其他过滤器(h / t弗拉基米尔)和一些难看的东西

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_jsonfrom_json将元组对转换为列表(JMESPath for Python会忽略元组)

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

json_query选择所需的dbuser

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