skip to Main Content

I have a json file in the format

{
  "hello": [
    {
      "name": "var1",
      "value": "1234"
    },
    {
      "name": "var2",
      "value": "2356"
    },
    {
      "name": "var3",
      "value": "2356"
    }
  ],
  "hi": [
    {
      "name": "var1",
      "value": "3412"
    },
    {
      "name": "var2",
      "value": "2563"
    },
    {
      "name": "var3",
      "value": "4256"
    }
  ],
  "bye": [
    {
      "name": "var1",
      "value": "1294"
    },
    {
      "name": "var2",
      "value": "8356"
    },
    {
      "name": "var3",
      "value": "5356"
    }
  ]
}

I want to convert this object into this format

{
  "output": [
    {
      "var1": {
        "hello": "1234",
        "hi": "3412",
        "bye": "1294"
      }
    },
    {
      "var2": {
        "hello": "2356",
        "hi": "2563",
        "bye": "8356"
      }
    },
    {
      "var3": {
        "hello": "2356",
        "hi": "4256",
        "bye": "5356"
      }
    }
  ]
}

so far i’ve tried multiple ways using to_entries and map functions in jq to create the contents inside the output variable
jq 'to_entries | map(.value[]| . += {"key_v" : (.key)} )' input.json > output.json this is the closest i came to a solution

  • extracting keys and add to the key value pair of the object
  • use map(select()) to group by keys
    but i am getting errors in both the steps such as cannot index array with string name or string value.

2

Answers


  1. A simple solution is readily obtained if the following stream-oriented "coalesce" function is used:

    # s is assumed to be a stream of objects for which
    # the values for each distinct key are summable.
    # Output: a single object formed by adding 
    # the $v values of each distinct key.
    def coalesce(s):
      reduce (s | to_entries[]) as {key: $k, value: $v} ({};
        .[$k] += $v);
    

    The solution is now simply:

    coalesce(to_entries[]
             | .key as $key
             | .value[]
             | {(.name): {($key): .value}})
    | {output: [.]}
    
    Login or Signup to reply.
  2. It doesn’t win a beauty contest, but it works:

    with_entries(.value |= from_entries)
    | with_entries(.key as $key | .value[] |= {($key):.})
    | reduce .[] as $item ({}; . * $item)
    

    With a single call to with_entries:

    with_entries(.key as $key | .value |= (from_entries | map_values({($key):.})))
    | reduce .[] as $item ({}; . * $item)
    

    Output:

    {
      "var1": {
        "hello": "1234",
        "hi": "3412",
        "bye": "1294"
      },
      "var2": {
        "hello": "2356",
        "hi": "2563",
        "bye": "8356"
      },
      "var3": {
        "hello": "2356",
        "hi": "4256",
        "bye": "5356"
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search