Reputation: 3
Here are my two json files content:
file1.json
{
"nodes": [
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-A"
},
{
"pm_addr": "192.100.0.6",
"name": "TB1-OSC-B"
},
{
"pm_addr": "192.100.0.7",
"name": "TB1-OSC-C"
}
]
}
file2.json
{
"nodes": [
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-D"
}
]
}
I want to add the contents of file2.json to file1.json but after the json object : TB1-OSC-B i.e., second json entry. In this case the entry is present at second location but it may be present any where else aswell. My final json file should look like this:
file3.json
{
"nodes": [
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-A"
},
{
"pm_addr": "192.100.0.6",
"name": "TB1-OSC-B"
},
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-D"
},
{
"pm_addr": "192.100.0.7",
"name": "TB1-OSC-C"
}
]
}
I am using jq version : 1.3 and I have no way to upgade it. I tried using add and =+ parameters provided by jq. But it did not help.
Thanks in advnace
Upvotes: 0
Views: 721
Reputation: 116967
The key to a clear and maintainable solution is having suitable utility functions.
def insert_at(i; x): .[:i] + [x] + .[i:];
def indicesof(f):
. as $in
| range(0;length) | select( $in[.] | f );
def insert_after(f; x):
[indicesof(f)] as $ix
| if ($ix|length) > 0
then insert_at($ix[0]+1; x)
else . end;
jq 1.4 allows a more efficient solution, courtesy of first/1
:
def insert_at($i; $x): .[:$i] + [$x] + .[$i:];
def indicesof(f):
. as $in
| range(0;length) | select( $in[.] | f );
def insert_after(f; $x):
(first(indicesof(f)) // null) as $i
| if $i then insert_at($i + 1; $x) else . end;
With these utility functions, solutions to the given problem can be expressed directly. For example, assuming an invocation along the lines of:
jq -s -f merge.jq file1.json file2.json
.[1].nodes[0] as $file2
| .[0]
| .nodes |= insert_after(.name == "TB1-OSC-B"; $file2)
This can easily be modified depending on the detailed requirements.
Upvotes: 2
Reputation: 47219
If you wanted to append the object from file2.json
to the nodes
array it is fairly straightforward:
jq -s '.[0].nodes += [ .[1].nodes[0] ] | .[0]' file1.json file2.json
Output:
{
"nodes": [
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-A"
},
{
"pm_addr": "192.100.0.6",
"name": "TB1-OSC-B"
},
{
"pm_addr": "192.100.0.7",
"name": "TB1-OSC-C"
},
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-D"
}
]
}
However, because you want to insert the object, it becomes more tricky, as jq
AFAIK does not support insertion into arrays, only prepending and appending.
Below is a rather convoluted example of how to do this by splicing it in:
parse.jq
# Find the desired index and store it as $n
(.[0].nodes | map(.name == "TB1-OSC-B") | index(true)) as $n |
# Splice the object from the second file into the first
.[0].nodes = .[0].nodes[0:($n|tonumber+1)] +
[ .[1].nodes[0] ] +
.[0].nodes[($n|tonumber+1):(.[0].nodes|length)] |
# Only output the now modified object from the first file
.[0]
Run it like this:
jq -sf parse.jq file1.json file2.json
Output in this case:
{
"nodes": [
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-A"
},
{
"pm_addr": "192.100.0.6",
"name": "TB1-OSC-B"
},
{
"pm_addr": "192.100.0.4",
"name": "TB1-OSC-D"
},
{
"pm_addr": "192.100.0.7",
"name": "TB1-OSC-C"
}
]
}
Upvotes: 2