我跟随json:
{
"vertices": [
{
"__cp": "foo",
"__type": "metric",
"__eid": "foobar",
"name": "Undertow Metrics~Sessions Created",
"_id": 45056,
"_type": "vertex"
},
...
]
"edges": [
...
我想实现这种格式:
{
"nodes": [
{
"cp": "foo",
"type": "metric",
"label": "metric: Undertow Metrics~Sessions Created",
"name": "Undertow Metrics~Sessions Created",
"id": 45056
},
...
]
"edges": [
...
到目前为止,我能够创建这个表达式:
jq '{nodes: .vertices} | del(.nodes[]."_type", .nodes[]."__eid")'
即。重命名'顶点'到节点'并删除' _type'和' __ eid',如何重命名嵌套在JSON中更深的密钥?
答案 0 :(得分:2)
如果使用with_entries(filter)
,则可以更改对象属性的名称。这会将对象转换为键/值对数组,并将过滤器应用于对并转换回对象。因此,您只想将这些对象的密钥更新为新名称。
根据您使用的jq版本,下一部分可能会非常棘手。字符串替换在jq 1.5之前不会被引入。如果可以,那么你可以这样做:
{
nodes: .vertices | map(with_entries(
.key |= sub("^_+"; "")
)),
edges
}
否则,如果你使用的是jq 1.4,那么你必须手动删除它们。递归函数可以帮助解决这个问题,因为下划线的数量会有所不同。
def ltrimall(str): str as $str |
if startswith($str)
then ltrimstr($str) | ltrimall(str)
else .
end;
{
nodes: .vertices | map(with_entries(
.key |= ltrimall("_")
)),
edges
}
答案 1 :(得分:1)
以下程序适用于jq 1.4或jq 1.5。 它使用walk / 1从任何键中删除前导下划线,无论它在输入JSON中出现在何处。
此处提供的ltrim版本使用recurse / 1来提高效率和便携性,但可以使用任何合适的替代品。
def ltrim(c):
reduce recurse( if .[0:1] == c then .[1:] else null end) as $x
(null; $x);
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
.vertices = .nodes
| del(.nodes)
| (.vertices |= walk(
if type == "object"
then with_entries( .key |= ltrim("_") )
else .
end ))
答案 2 :(得分:1)
从您的示例数据看起来您打算进行大量的操作,因此我会将事情分解为以下几个阶段:
.nodes = .vertices # \ first take care of renaming
| del(.vertices) # / .vertices to .nodes
| .nodes = [
.nodes[] # \ then scan each node
| . as $n # /
| del(._type, .__eid) # \ whatever key-specific tweaks like
| .label = "metric: \(.name)" # / calculating .label you want can go here
| reduce keys[] as $k ( # \
{}; # | final reduce to handle renaming
.[$k | sub("^_+";"")] = $n[$k] # | any keys that start with _
) # /
]