如何使用 jq 和 map 从复杂 JSON 中获取对象的键值对? (活动活动)
How to get key value pairs of the objects from complex JSON using jq and map? (Active Campaign)
我关注 JSON。我想根据角色获取键值对对象。在此示例中有 3 个角色(Presenter、Approver、Customer),但可以有更多,因为它是动态的。
JSON
{
"Presenter Name": "Roney",
"Presenter Email": "roney@domain.com",
"Approver Name": "Tim",
"Approver Email": "tim@domain.com",
"Customer Name": "Alex",
"Customer Email": "alex@domain.com",
"Invoice": "001",
"Date": "2022-02-14"
}
使用 jq、map 的预期输出
{
"Presenter": {
"email_address": "roney@domain.com",
"name": "Roney",
"role": "Presenter"
},
"Approver": {
"email_address": "tim@domain.com",
"name": "Tim",
"role": "Approver"
},
"Customer": {
"email_address": "alex@domain.com",
"name": "Alex",
"role": "Customer"
}
}
我已经试过了,但不知道下一步该怎么做。请指教
to_entries |map( { (.key): { name: .value, email_address:.value, role: .key} } ) | add
这 split
是 space 字符处的键,同时丢弃其中没有的任何项目。然后它将三个字段相应地分配给它们的值,使用 reduce
组合分组。
to_entries
| map(.key |= split(" ") | select(.key[1]))
| reduce group_by(.key[0])[] as $g ({};
.[$g[0].key[0]] = (
INDEX($g[]; .key[1]) | {
email_address: .Email.value,
name: .Name.value,
role: .Name.key[0]
}
)
)
{
"Approver": {
"email_address": "tim@domain.com",
"name": "Tim",
"role": "Approver"
},
"Customer": {
"email_address": "alex@domain.com",
"name": "Alex",
"role": "Customer"
},
"Presenter": {
"email_address": "roney@domain.com",
"name": "Roney",
"role": "Presenter"
}
}
{ "Name": "name", "Email": "email_address" } as $key_map |
to_entries |
map (
( .key | split(" ") | select( length == 2 ) ) as [ $role, $raw_key ] |
[ $role, "role", $role ],
[ $role, $key_map[$raw_key], .value ]
) |
reduce .[] as [ $role, $key, $val ] ( {}; .[ $role ][ $key ] = $val )
Demo 在 jqplay
在上面,我们从统一数据开始。具体来说,我们首先生成以下内容:
[
[ "Presenter", "role", "Presenter" ],
[ "Presenter", "name", "Roney" ],
[ "Presenter", "role", "Presenter" ],
[ "Presenter", "email_address", "roney@domain.com" ],
[ "Approver", "role", "Approver" ],
[ "Approver", "name", "Tim" ],
[ "Approver", "role", "Approver" ],
[ "Approver", "email_address", "tim@domain.com" ],
[ "Customer", "role", "Customer" ],
[ "Customer", "name", "Alex" ],
[ "Customer", "role", "Customer" ],
[ "Customer", "email_address", "alex@domain.com" ]
]
有冗余信息,但没关系。
然后,最后的简单 reduce
构建所需的结构。
.key | split(" ") | select( length == 2 )
可以换成更安全的
.key | match("^(.*) (Name|Email)$") | .captures | map( .string )
这是另一种不使用 group_by
的较短方法。相反,这直接使用 reduce
遍历初始对象,如果键遵循 space-separated role-key 模式,则立即相应地设置所有字段。
reduce (to_entries[] | .key /= " ") as {key: [$role, $key], $value} ({};
if $key then
.[$role] += {({Email: "email_address", Name: "name"}[$key]): $value, $role}
else . end
)
{
"Presenter": {
"name": "Roney",
"role": "Presenter",
"email_address": "roney@domain.com"
},
"Approver": {
"name": "Tim",
"role": "Approver",
"email_address": "tim@domain.com"
},
"Customer": {
"name": "Alex",
"role": "Customer",
"email_address": "alex@domain.com"
}
}
我关注 JSON。我想根据角色获取键值对对象。在此示例中有 3 个角色(Presenter、Approver、Customer),但可以有更多,因为它是动态的。
JSON
{
"Presenter Name": "Roney",
"Presenter Email": "roney@domain.com",
"Approver Name": "Tim",
"Approver Email": "tim@domain.com",
"Customer Name": "Alex",
"Customer Email": "alex@domain.com",
"Invoice": "001",
"Date": "2022-02-14"
}
使用 jq、map 的预期输出
{
"Presenter": {
"email_address": "roney@domain.com",
"name": "Roney",
"role": "Presenter"
},
"Approver": {
"email_address": "tim@domain.com",
"name": "Tim",
"role": "Approver"
},
"Customer": {
"email_address": "alex@domain.com",
"name": "Alex",
"role": "Customer"
}
}
我已经试过了,但不知道下一步该怎么做。请指教
to_entries |map( { (.key): { name: .value, email_address:.value, role: .key} } ) | add
这 split
是 space 字符处的键,同时丢弃其中没有的任何项目。然后它将三个字段相应地分配给它们的值,使用 reduce
组合分组。
to_entries
| map(.key |= split(" ") | select(.key[1]))
| reduce group_by(.key[0])[] as $g ({};
.[$g[0].key[0]] = (
INDEX($g[]; .key[1]) | {
email_address: .Email.value,
name: .Name.value,
role: .Name.key[0]
}
)
)
{
"Approver": {
"email_address": "tim@domain.com",
"name": "Tim",
"role": "Approver"
},
"Customer": {
"email_address": "alex@domain.com",
"name": "Alex",
"role": "Customer"
},
"Presenter": {
"email_address": "roney@domain.com",
"name": "Roney",
"role": "Presenter"
}
}
{ "Name": "name", "Email": "email_address" } as $key_map |
to_entries |
map (
( .key | split(" ") | select( length == 2 ) ) as [ $role, $raw_key ] |
[ $role, "role", $role ],
[ $role, $key_map[$raw_key], .value ]
) |
reduce .[] as [ $role, $key, $val ] ( {}; .[ $role ][ $key ] = $val )
Demo 在 jqplay
在上面,我们从统一数据开始。具体来说,我们首先生成以下内容:
[
[ "Presenter", "role", "Presenter" ],
[ "Presenter", "name", "Roney" ],
[ "Presenter", "role", "Presenter" ],
[ "Presenter", "email_address", "roney@domain.com" ],
[ "Approver", "role", "Approver" ],
[ "Approver", "name", "Tim" ],
[ "Approver", "role", "Approver" ],
[ "Approver", "email_address", "tim@domain.com" ],
[ "Customer", "role", "Customer" ],
[ "Customer", "name", "Alex" ],
[ "Customer", "role", "Customer" ],
[ "Customer", "email_address", "alex@domain.com" ]
]
有冗余信息,但没关系。
然后,最后的简单 reduce
构建所需的结构。
.key | split(" ") | select( length == 2 )
可以换成更安全的
.key | match("^(.*) (Name|Email)$") | .captures | map( .string )
这是另一种不使用 group_by
的较短方法。相反,这直接使用 reduce
遍历初始对象,如果键遵循 space-separated role-key 模式,则立即相应地设置所有字段。
reduce (to_entries[] | .key /= " ") as {key: [$role, $key], $value} ({};
if $key then
.[$role] += {({Email: "email_address", Name: "name"}[$key]): $value, $role}
else . end
)
{
"Presenter": {
"name": "Roney",
"role": "Presenter",
"email_address": "roney@domain.com"
},
"Approver": {
"name": "Tim",
"role": "Approver",
"email_address": "tim@domain.com"
},
"Customer": {
"name": "Alex",
"role": "Customer",
"email_address": "alex@domain.com"
}
}