用于展平对象数组的 JMESPath 表达式,每个对象都有嵌套的对象数组 [英] JMESPath expression to flatten array of objects, each with nested arrays of objects
问题描述
我有一个包含数据库数组的 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_json
和 from_json
将元组对转换为列表(JMESPath for Python 忽略元组)
[ [{"db": "db_a", "users": [{"name": "alice"}, {"name": "alex"}]},{"name": "alice"}],...]
json_query
选择所需的 db
和 user
值
[ {"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屋!