skip to Main Content

I have two simple JSON objects, I’m trying to add a single object from a Bash variable newValArr in order of the corresponding objects to the masterfile.json. They appear as following:

newValArr

[{ "firstValue": "foo", "secondValue": "bar"},
 { "firstValue": "baz", "secondValue": "qux"},
 ...
]

masterfile.json

{
  "value": [
    {
      "id": "abc",
      "properties": {
        "blah": "stuff"
      }
    },
    {
      "id": "def",
      "properties": {
        "blah": "morestuff"
      }
    },
...
  ]
}

I’ve created the following in Bash that adds the firstValue and secondValue object in the intended spot in the value array of objects, here is the script:

jq --argjson newvalues "${newValArr}" '.value[].properties.newObject += $newvalues[0]' masterfile.json > newoutput.json

And here is the current JSON output:

newoutput.json

{
  "value": [
    {
      "id": "abc",
      "properties": {
        "blah": "stuff",
        "newObject": {
          "firstValue": "foo", 
          "secondValue": "bar"
        }
      }
    },
    {
      "id": "def",
      "properties": {
        "blah": "otherstuff",
        "newObject": {
          "firstValue": "foo", 
          "secondValue": "bar"
        }
      }
    },
...
  ]
}

With the desired output being:

{
  "value": [
    {
      "id": "abc",
      "properties": {
        "blah": "stuff",
        "newObject": {
          "firstValue": "foo", 
          "secondValue": "bar"
        }
      }
    },
    {
      "id": "def",
      "properties": {
        "blah": "otherstuff",
        "newObject": {
          "firstValue": "baz", 
          "secondValue": "qux"
        }
      }
    },
...
  ]
}

The problem obviously is that the same newValArr object is being placed into every single newObject as we’re continually referencing the same index. If we don’t specify the index, then all the newValArr objects will be placed into each newObject, and I’m not quite sure if it’s even possible to iterate through the indexes in JQ like we would in Bash using newValArr[@] for example so that each index could be assigned in order. Is this possible in JQ? Or must an entirely different method be used?
The two JSON’s will always have the same number of objects, in the same order, no need to worry about that.

I’ve looked into implementing this using to_entires, however it doesn’t seem compatible with what I’m trying to accomplish.

2

Answers


  1. One way to do it is create a range of all the indexes of the arrays and build a new object by combining the corresponding elements:

    #!/usr/bin/env bash
    
    newValArr='
    [{ "firstValue": "foo", "secondValue": "bar"},
     { "firstValue": "baz", "secondValue": "qux"}
    ]
    '
    
    jq -n --argjson newval "$newValArr" --argfile master masterfile.json '
       { value: [ range($master.value | length)
                  | . as $n
                  | $master.value[$n] * { properties: { newObject: $newval[$n] } }
                ]
       }'
    

    outputs

    {
      "value": [
        {
          "id": "abc",
          "properties": {
            "blah": "stuff",
            "newObject": {
              "firstValue": "foo",
              "secondValue": "bar"
            }
          }
        },
        {
          "id": "def",
          "properties": {
            "blah": "morestuff",
            "newObject": {
              "firstValue": "baz",
              "secondValue": "qux"
            }
          }
        }
      ]
    }
    

    Or another approach that uses transpose to zip the two arrays together and then merges them:

    jq --argjson newval "$newValArr" '
       .value |= [ [ ., $newval ] | transpose[] | .[0] * { properties: { newObject: .[1] }} ]
    ' masterfile.json
    
    Login or Signup to reply.
  2. You could use to_entries which, when applied to an array, generates indices in the .key field, which then can be used to index into the imported variable. Then, just map over the result array to construct your final objects.

    jq --argjson vals "$newValArr" '.value |= (to_entries | map(
      $vals[.key] as $newObject | .value | .properties += {$newObject}
    ))' masterfile.json
    
    {
      "value": [
        {
          "id": "abc",
          "properties": {
            "blah": "stuff",
            "newObject": {
              "firstValue": "foo",
              "secondValue": "bar"
            }
          }
        },
        {
          "id": "def",
          "properties": {
            "blah": "morestuff",
            "newObject": {
              "firstValue": "baz",
              "secondValue": "qux"
            }
          }
        }
      ]
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search