Issue
I'm trying to generate a new json from an existing one. In the new json is an array with one entry, which needs to remain the first entry in the array. With jq generate additional entries to this arrays. But my code replaces the existing entry. I've created a smaller representation of my Problem.
This following code is what I have so far.
echo '{"Results": [{"Input": [{"foo":" bar", "this": "that"}, {"foo": "bing"}]}]}' | \
jq '{"sections": [{"first": "element", "that": "is needed at pos 0 in this array"}, .Results[] | .Input[]? | {"markdown": true, "facts":[{name: "MyFoo", value: .foo}]}]}'
This is the result i, which is missing the first element of the sections list.
{
"sections": [
{
"markdown": true,
"facts": [
{
"name": "MyFoo",
"value": " bar"
}
]
},
{
"markdown": true,
"facts": [
{
"name": "MyFoo",
"value": "bing"
}
]
}
]
}
My desired result would be the following:
{
"sections": [
{
"first": "element",
"that": "is needed at pos 0 in this array"
},
{
"markdown": true,
"facts": [
{
"name": "MyFoo",
"value": " bar"
}
]
},
{
"markdown": true,
"facts": [
{
"name": "MyFoo",
"value": "bing"
}
]
}
]
}
I'v tried to use two linked jq command but his destroys the order in the sections list.
echo '{"Results": [{"Input": [{"foo":" bar", "this": "that"}, {"foo": "bing"}]}]}' | \
jq '{"sections": [ .Results[] | .Input[]? | {"markdown": true, "facts":[{name: "MyFoo", value: .foo}]}]}' |\
jq '.sections += [{"first": "element", "that": "is needed at pos 0 in this array"}]'
Solution
You are almost there. Let's format your attempt a bit, to understand what it does:
{
"sections": [
{"first": "element", "that": "is needed at pos 0 in this array"},
.Results[] | .Input[]? | {"markdown": true, "facts": [{name: "MyFoo", value: .foo}]}
]
}
I formatted it according to your intent: you want an object whose sections
property is an array that has the object { "first": "element" ... }
as its first item and the other items are computed from the properties .Results.Input
of the input object.
Unfortunately, the documentation of jq
does not specify the precedence of its operators. While everybody (including me) assumes that the pipe operator (|
) has higher precedence than the comma operator (,
) (an assumption probably based on how these operators work in the languages inspired from C), in jq
is the other way around: ,
has higher precedence than |
.
This makes your code work equivalent to this:
{
"sections": [
({"first": "element", "that": "is needed at pos 0 in this array"}, .Results[])
| .Input[]? | {"markdown": true, "facts": [{name: "MyFoo", value: .foo}]}
]
}
The first filter ({"first": ... }, .Results[]
) produces:
{
"sections":[
{"first": "element","that":"is needed at pos 0 in this array"},
{"Input": [{"foo": " bar","this": "that"}, {"foo": "bing"}]}
]
}
The next filter, .Input[]
discards the object {first: "element" ...}
and its output is [{"foo": " bar","this": "that"}, {"foo": "bing"}]
and now it is clear why the output of the entire program is not the one that you expect.
The solution is simple: wrap the pipeline that processes the input in parentheses and it will work.
Given that jq
language is not JSON (but it includes JSON), you don't have to wrap the keys in quotes. Getting rid of the quotes around keys and wrapping the program on multiple lines makes it easier to read:
{
sections: [
{ first: "element", that: "is needed at pos 0 in this array" },
(.Results[] | .Input[]? | { markdown: true, facts: [{ name: "MyFoo", value: .foo }]})
]
}
Check it online on the jq
playground.
Answered By - axiac Answer Checked By - Senaida (WPSolving Volunteer)