Home > database >  write bash-array to json with jq: one element per object
write bash-array to json with jq: one element per object

Time:02-14

I'm trying to save some values from a bash-array into an existing json. I tried some different approaches, but I didn't manage to solve the issue. What am I missing here?

input.json

{
"type": "FeatureCollection",
"name": "test",
"features": [
{ "type": "Feature", "properties": { "OBJECTID": 3213, "USE": "dem", "tile": "4045644"}},
{ "type": "Feature", "properties": { "OBJECTID": 3214, "USE": "dem", "tile": "4045646"}},
{ "type": "Feature", "properties": { "OBJECTID": 3215, "USE": "dem", "tile": "4045648"}}
]
}

Output of some calculations in Bash - 100% derived from input.json. So this array length == length of the "features[]"-array in the input.json

printf '%s\n' "${pushintojson[@]}"

4045646 NV NV NV 
4045648 NV 4045644 NV 
4045650 NV 4045646 NV 
jq '.features |= map(.properties  =  {NOSW: $ARGS.positional})' --args "${pushintojson[@]}"  <<< "${input.json}"

So this produces this (newlines added by me for readability):

{
"type":"FeatureCollection",
"name":"test",
"features": [
{"type":"Feature","properties":{"OBJECTID":3213,"USE":"dem","tile":"4045644",
"NOSW":[
"4045646 NV NV NV",
"4045648 NV 4045644 NV",
"4045650 NV 4045646 NV"
]}},

{"type":"Feature","properties":{"OBJECTID":3214,"USE":"dem","tile":"4045646",
"NOSW":[
"4045646 NV NV NV",
"4045648 NV 4045644 NV",
"4045650 NV 4045646 NV"
]}},

{"type":"Feature","properties":{"OBJECTID":3215,"USE":"dem","tile":"4045648",
"NOSW":[
"4045646 NV NV NV",
"4045648 NV 4045644 NV",
"4045650 NV 4045646 NV"
]}}
]
}

All values of the bash-array are saved to EVERY element. It's supposed to be just one value per json-object - actually as an array itself. So in pseudo: "pushintojson[0]" needs to be under "features[0]", pushintojson[1]" to "features[1]" pushintojson[2]" to "features[2]" etc.

DESIRED OUTPUT

{
"type":"FeatureCollection",
"name":"test",
"features": [
{"type":"Feature","properties":{"OBJECTID":3213,"USE":"dem","tile":"4045644",
"NOSW":"4045646 NV NV NV"
}},
{"type":"Feature","properties":{"OBJECTID":3214,"USE":"dem","tile":"4045646",
"NOSW":"4045648 NV 4045644 NV"
}},
{"type":"Feature","properties":{"OBJECTID":3215,"USE":"dem","tile":"4045648",
"NOSW":"4045650 NV 4045646 NV"
}}
]
}

CodePudding user response:

If you only use map then for each element you end up iterating over all arguments again. Instead, you have to align the .features array to the $ARGS.positional array.

One way, which is closer to your attempt, is to expand the .features array using to_entries to fit the array's elements with their keys, which in turn can be used within map to reference by index the corresponding item of the $ARGS.positional array.

jq '
  .features |= (to_entries | map(
    .value * {properties: {NOSW: $ARGS.positional[.key]}}
  ))
' --args "${pushintojson[@]}" < input.json

Another approach would be to use transpose to generate an array of aligned items from both initial arrays, and then again just map their contents together.

jq '
  .features |= ([., $ARGS.positional] | transpose | map(
    .[0] * {properties: {NOSW: .[1]}}
  ))
' --args "${pushintojson[@]}" < input.json

Both produce

{
  "type": "FeatureCollection",
  "name": "test",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "OBJECTID": 3213,
        "USE": "dem",
        "tile": "4045644",
        "NOSW": "4045646 NV NV NV"
      }
    },
    {
      "type": "Feature",
      "properties": {
        "OBJECTID": 3214,
        "USE": "dem",
        "tile": "4045646",
        "NOSW": "4045648 NV 4045644 NV"
      }
    },
    {
      "type": "Feature",
      "properties": {
        "OBJECTID": 3215,
        "USE": "dem",
        "tile": "4045648",
        "NOSW": "4045650 NV 4045646 NV"
      }
    }
  ]
}
  • Related