5

Below is the template of my employee.json file

{
    "orgConfig": {
        "departments": []
    }
}

where departments will have array of departments like below

{
    "name" : "physics",
    "id" : "1234",
    "head" : "abcd"
}

similarly

{
    "name" : "chemistry",
    "id" : "3421",
    "head" : "xyz"
}

so the final array structure i want to construct is as below

{
    "orgConfig": {
        "departments": [
            {
                "name" : "physics",
                "id" : "1234",
                "head" : "abcd"
            },
            {
                "name" : "chemistry",
                "id" : "3421",
                "head" : "xyz"
            },
            {
                "name" : "Maths",
                "id" : "4634",
                "head" : "jklm"
            }
        ]
    }
}

Below is the code where i am adding the json elements to an departments array dynamically

#!/bin/bash

source department.properties   # will have departments=physiscs,chemistry,Maths,computers .. etc
IFS=',' read -ra NAMES <<< "$departmentsToImport"

position=0
for i in "${NAMES[@]}"; do
    #./jsonfiles will chemistry.json, physics.json, Maths.json etc
    value=`cat ./jsonfiles/$i.json`    

    if [ $position -eq 0 ]
    then
       cat employee.json | jq --arg value "$value" '.orgConfig.departments[0] |= .+ $value' > tmp.json && mv tmp.json employee.json
    else
       cat employee.json | jq --arg position "$position" value "$value" '.orgConfig.departments[$position] |= .+ $value' > tmp.json && mv tmp.json employee.json
    fi
    ((position++))
    rm -rf tmp.json
done

exit $?

but program throws below error

jq: error (at <stdin>:51): Cannot index array with string "1"

But if use direct index instead of variable position then it works fine.

cat employee.json | jq --argjson value "$value" '.orgConfig.departments[1] |= .+ $value' > tmp.json && mv tmp.json employee.json 

I do not know how many key value maps of departments i have. I cannot hard code the index. Any help to above problem and Dynamically add json object into array?

Thanks

2 Answers 2

4

This can be done by turning off jq's automatic input reading, then piping the first explicit input through a filter that modifies its input using the remaining explicit inputs. Make sense? No :) But the code itself is simple:

jq -n 'input | .orgConfig.departments += [inputs]' \
  employee.json chemistry.json physics.json math.json
  1. The first input reads from the first argument (employee.json).
  2. The += gets its input from the input filter. Its left operand selects the field to update; the right operand provides the value to update it with.
  3. inputs reads from the remaining command-line arguments, and puts their contents in an array, each file in a separate element.

Combining this with your shell code to select the correct course files yields

source department.properties
IFS=, read -ra NAMES <<< "$departmentsToImport"
for c in "${NAMES[@]}"; do
    courses+=("./jsonfiles/$c.json")
done
jq -n 'input | .orgConfig.departments += [inputs]' employee.json "${courses[@]}"
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @chepner for the great help. Solved my issue.
4

The task can be accomplished without invoking jq more than once.

Something very much like the following should suffice:

jq -s '{orgConfig: {departments: . }}' jsonfiles/*.json

This solution of course assumes the .json files all hold valid JSON.

The trick is to use the -s (aka --slurp) option, as this converts the input into an array for you. You'll probably find that using -s results in better run-times than some other approaches.

1 Comment

Thanks @peak, got new requirements based on solution u gave above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.