用于展平对象数组的 JMESPath 表达式,每个对象都有嵌套的对象数组 [英] JMESPath expression to flatten array of objects, each with nested arrays of objects

查看:21
本文介绍了用于展平对象数组的 JMESPath 表达式,每个对象都有嵌套的对象数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含数据库数组的 JSON,每个数据库都有一个用户数组,例如

{"数据库": [{"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 评论``暗示了这一点

<块引用>

在进行迭代时不能引用父项.为什么?迭代的所有选项,[*] 和映射,都使用迭代项作为任何表达式的上下文.没有机会获得任何其他值

解决方案

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

在 Ansible 上,它可以用其他过滤器(h/t Vladimir)来完成,还有一些丑陋

databases_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"},...]

I have JSON containing an array of databases, each database has an array of users, e.g.

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

I would like to produce a flat array of databases and users, i.e.

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

In SQL terms this would be a cartesian join or cartesian product, but I'm not sure of the correct term in a tree structure. The closest I've got so far is

databases[].users[]

which produces

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

and

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

which produces

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

Addendum: I'm happy to accept "You can't do that with JMESPath, here's why ..." as an answer. An HN Comment`` hints at this

can't reference parents when doing iteration. Why? All options for iteration, [* ] and map, all use the iterated item as the context for any expression. There's no opportunity to get any other values in

解决方案

You can't do this with just JMESPath, because JMESPath expressions can only refer to a single scope. There's no way to reach the outer scope (database objects), when the current scope is a user object. JEP 11 would allow access to other scopes, but it hasn't been accepted after several years.

On Ansible it can be done with other filters (h/t Vladimir), and some ugliness

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

Explanation

As a reminder, our starting point is

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

the subelements filter transforms this into a list of Python tuple pairs

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

to_json and from_json convert the tuple pairs to lists (JMESPath for Python ignores tuples)

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

json_query selects the desired db and user values

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

这篇关于用于展平对象数组的 JMESPath 表达式,每个对象都有嵌套的对象数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆