Given the following JSON:
{
"one": "1",
"two": "2",
"flag": "f1 f2 f3",
"test one": "",
"test two": "",
"test three": ""
}
Is it possible to obtain the following result using jq?
{
"one": "1",
"two": "2",
"flags": ["f1", "f2", "f3"],
"tests": ["one", "two", "three"]
}
Three points are crucial:
Leave unchanged any field that is not
flag
or starts withtest
Transform
flag
(space separated values) into an arrayAny field that starts with
test
is added to an array (tests
) where the value is the remaining part of the field's name
CodePudding user response:
You can use /=
to update by splitting, startswith
to match at the beginnning of a string, and to_entries
and with_entries
to manipulate entries involving the key name:
jq '
.flag /= " "
| .tests = (to_entries | map(.key | select(startswith("test "))[5:]))
| with_entries(select(.key | startswith("test ") | not))
'
Another, maybe more efficient implementation which loops just once through the object using reduce
could be:
jq '
reduce to_entries[] as {$key, $value} (null;
if $key == "flag" then .flag = $value / " "
elif $key | startswith("test ") then .tests = [$key[5:]]
else .[$key] = $value end
)
'
Given the sample data, both produce:
{
"one": "1",
"two": "2",
"flag": [
"f1",
"f2",
"f3"
],
"tests": [
"one",
"two",
"three"
]
}