Replacing values in JSON using values from another file with jq - json

I have a json file with city names in it and I would like to replace them with particular city codes from another file. The data.json is roughly:
{
"Customer": {
"CustomerName": "Customer1",
"City": "Cityname1"
}
}
{
"RelevantObject": false
}
{
"Customer": {
"CustomerName": "Customer2",
"City": "Cityname2"
}
}
# {...
The code list can be anything that is the easiest to feed to jq, I've been trying with codes.json:
{
"Cityname1": "Code1",
"Cityname2": "Code2"
}
but like I said, any format is fine. The hoped result:
{
"Customer": {
"CustomerName": "Customer1",
"City": "Code1"
}
}
{
"RelevantObject": false
}
{
"Customer": {
"CustomerName": "Customer2",
"City": "Code2"
}
}
I've been trying to read the file in with jq --argfile codes codes.json but I've had a hard time of referring to the $codes in the jq: .Customer.City=$codes.??

The key to a good answer here is:
.Customer.City |= $codes[.]

jq --argfile codes codes.json 'select(.Customer?)|{(.Customer.City):$codes[.Customer.City]}' data.json | jq -n '[inputs] | add'

Related

iterate on key to get the contents of the key

IF I have json that looks like
{
"items": [
{
"name": "issue1",
"spec": {
"config": {
"setting1": abc,
"setting2": {
"name": "xyz"
}
},
"files": {
"name": "cde",
"path": "/home"
},
"program": {
"name": "apache"
}
}
}
]
}
and I want to have iteration at .items[0].spec where the key config,files,program's contents can be shown.. something like
config:
{
"setting1": abc,
"setting2": {
"name": "xyz"
}
}
files:
{
"name": "cde",
"path": "/home"
}
program:
{
"name": "apache"
}
and there might be things more or less than config/files/programs for each items.
I know that I can get the list of keys by jq -r '.items[0].spec| to_entries[].key' but not sure about formating the output and getting the contents of .items[].spec.xxxxx like above.
I also got very close by jq -r '{test: .items[0].spec | with_entries(select(.value != null)) }' but I want to seperate each item per key
Also this got me even closer! but how do you get the json syntax of the object to display uncompressed?
jq -r '.items[].spec | keys[] as $k | "\($k):\n \(.[$k])"'
The "," operator is the magic ingredient you seem to be looking for:
.items[].spec | keys[] as $k | $k, .[$k]

How to prevent escaping when adding JSON object with jq?

I am working with jq and I am trying to add a new JSON object to a new key to an existing file.
I have the following JSON file, foobarbaz.json :
{
"example":{
"name": "stackOverflowQuestion"
}
}
I want to add a new entry under example, so to get the following output in foobar.json
{
"example": {
"name": "stackOverflowQuestion",
"new": {
"newfield": {
"key": "value"
}
}
}
}
I am using the following commands in the terminal:
$ tempvar='{"newfield":{"key":"value"}}'
$ cat foobarbaz.json | jq '.example.new=env.tempvar' > foobar.json
However, the output in foobar.json is somewhat unexpected:
{
"example": {
"name": "stackOverflowQuestion",
"new": "{\"newfield\":{\"key\":\"value\"}}"
}
}
Why does jq wrap the curly brackets with quotes, and why does it escape the double quotes?
Use fromjson to convert your string (the format all environment variables are in!) to the corresponding data structure, by decoding it as JSON content.
tempvar='{"newfield":{"key":"value"}}' jq '.example.new=(env.tempvar | fromjson)' <<'EOF'
{
"example":{
"name": "stackOverflowQuestion"
}
}
EOF
...emits as output:
{
"example": {
"name": "stackOverflowQuestion",
"new": {
"newfield": {
"key": "value"
}
}
}
}
Use the --argjson option to pass the pre-existing JSON snippet as a variable to the filter.
$ jq --argjson x "$tempvar" '.example.new=$x' foobarbaz.json
{
"example": {
"name": "stackOverflowQuestion",
"new": {
"newfield": {
"key": "value"
}
}
}
}
Note that tempvar isn't strictly necessary and can be dropped, if you are only defining it for use with the filter:
$ jq '.example.new={newfield: {key: "value"}}' foobarbaz.json
{
"example": {
"name": "stackOverflowQuestion",
"new": {
"newfield": {
"key": "value"
}
}
}
}

How to delete array elements that end with 1?

I need to remove all array elements that have the name field ending with 1.
Input:
{
"foo": "bar",
"data": {
"code": "abc123",
"items": [
{
"name": "exp1"
},
{
"name": "exp2"
},
{
"name": "exp11"
}
]
}
}
Desired output:
{
"foo": "bar",
"data": {
"code": "abc123",
"items": [
{
"name": "exp2"
}
]
}
}
My attempt:
jq 'del(.data.items[] | select(.name | endswith("1")))' input
Which results in Invalid path expression.
You can use this jq filter:
jq '.data.items|=map(select(.name|endswith("1")|not))' file
This replace .data.items with the a new array having objects whose names don't end with 1.
Your attempt will work with recent versions of jq (that is, more recent than version 1.5).
Yet another variant (perhaps the most concise robust alternative):
.data.items|=map(select(.name|test("[^1]$")))

jq - add new field with updating whole file

I have json file which is constructed in simmilar way:
[
{
"_id":"1234",
"org":"org1",
"int":
{"url":"http://url.com.uk:1234"}},
{
"_id":"4321",
"org":"org2",
"int":
{"url":"http://url.com.us:4321"}},
...
]
Now im "jumping" from one entry to another and checking if under URL application is working properly. After check i want to add/update field "status". But i can't update whole file, im just getting:
$ jq --arg mod "GOOD" '.[0].int + {stat: $mod}' tmp.json
{
"url": "http://url.com.uk:1234",
"stat": "GOOD"
}
How can i with jq command get new updated whole file, not just only part of it?
If you put your data in data.json and the changes you want to make to
each record into a separate arg.json argument file like
{
"1234": { "int": { "stat": "GOOD" } },
"4321": { "int": { "stat": "BAD", "xxx": "yyy" } }
}
and run jq as
$ jq -M --argfile arg arg.json 'map(. + $arg[._id])' data.json
then it will output the updated data, e.g.
[
{
"_id": "1234",
"org": "org1",
"int": {
"stat": "GOOD"
}
},
{
"_id": "4321",
"org": "org2",
"int": {
"stat": "BAD",
"xxx": "yyy"
}
}
]
Note that the + replaces keys. If you want to merge keys you can use * e.g.
$ jq -M --argfile arg arg.json 'map(. * $arg[._id])' data.json
which generates
[
{
"_id": "1234",
"org": "org1",
"int": {
"url": "http://url.com.uk:1234",
"stat": "GOOD"
}
},
{
"_id": "4321",
"org": "org2",
"int": {
"url": "http://url.com.us:4321",
"stat": "BAD",
"xxx": "yyy"
}
}
]
If you want to update the data in place you could use sponge
as described in the answer Manipulate JSON with jq
e.g.
$ jq -M --argfile arg arg.json 'map(. * $arg[._id])' data.json | sponge data.json
You can map to array and resign the int by operation, like:
jq --arg mod "GOOD" '.[] | .int=.int + {stat: $mod}' tmp.json
{
"_id": "1234",
"org": "org1",
"int": {
"url": "http://url.com.uk:1234",
"stat": "GOOD"
}
}
{
"_id": "4321",
"org": "org2",
"int": {
"url": "http://url.com.us:4321",
"stat": "GOOD"
}
}

jq json parser concate nested array object value

Hi I have the below JSON file with nested object:
{
"Maps": {
"Campus": [
{
"name": "nus",
"Building": [
{
"name": "sde1",
"Floor": [
{
"name": "floor1"
},
{
"name": "floor2"
}
]
},
{
"name": "sde2"
}
]
},
{
"name": "ntu",
"Building": [
{
"name": "ece1",
"Floor": [
{
"name": "floor1"
},
{
"name": "floor2"
}
]
},
{
"name": "ece2"
}
]
}
]
}
}
I want to use jq to parse the above JSON file and get the below format:
nus>sde1>floor1
nus>sde1>floor2
ntu>ece1>floor1
ntu>ece1>floor2
basically I have to concatenate the Campus Name with Building Name and Floor name and put a < symbol in between.
If the nested object field Floor is not exist, ignore the parse and continue the next child object.
How to achieve that? thanks.
You can use the following jq command:
jq '.Maps.Campus[]|"\(.name)>\(.Building[]|"\(.name)>\(.Floor[]?.name)")"' file.json
jq is smart enough to print the combinations of .name and .Building[].name since .Building is an array. The same action get's applied to .Building[].name and Floor[]?.name. ? because floor is not always set.
Here is a solution which uses jq variables
.Maps.Campus[]
| .name as $campus
| .Building[]
| .name as $bldg
| .Floor[]?
| .name as $floor
| "\($campus)>\($bldg)>\($floor)"