jsonjqedit

how to group_by with tables' key name


My input json file:

{ "london": [ "x", 0 ] }
{ "london": [ "y", 97 ] }
{ "paris": [ "x", 15 ] }
{ "paris": [ "y", 8 ] }

I try to group by key and make the output:

{ "london":  ["x", 0], ["y", 97] },
{ "paris":   ["x", 15], ["y", 8] }

or:

{ "london": [ {"x", 0}, {"y", 97} ] },
{ "paris":  [ {"x", 15}, {"y", 8} ] }

The following command give me an error message:

 jq -s 'group_by(keys_unsorted[0]) | map({(.[0]): map(.[1])})'

jq: error (at :4): Cannot index object with number

I try to change the numbers to strings, but, it does not help. I guess that I missed something in the map (?)

EDIT:

Extantion regarding the answer from @pmf. The Original source is:

 {
   "city": "london",
   "zoo": [
     { "room": { "name": "x" }, "gpu": { "id": "fish",  "sum": 0 } },
     { "room": { "name": "y" }, "gpu": { "id": "zebra", "sum": 97 } }
    ]
  }
  {
    "city": "paris",
    "zoo": [
       { "room": { "name": "x" }, "gpu": { "id": "fish",  "sum": 15 } },
       { "room": { "name": "y" }, "gpu": { "id": "zebra", "sum": 8 } }
    ]
  }

and I try to get the output as above. I started with following:

      jq -c '.city as $j | foreach .zoo[] as $i (.; .; {($j): [$i.room.name, $i.gpu.sum]})'

then i stuck and @pmf helped me. Can I do it else?


Solution

  • Your expected outputs aren't valid JSON (either they lack array brackets, or they have abundant commas). The first of the two even lists multiple values to a single object key, which is not possible (unless the value is enclosed within array brackets). Here's how to start collecting from a stream:

    jq -n 'reduce (inputs | to_entries)[] as $e ({}; .[$e.key] += [$e.value])'
    
    {
      "london": [
        [
          "x",
          0
        ],
        [
          "y",
          97
        ]
      ],
      "paris": [
        [
          "x",
          15
        ],
        [
          "y",
          8
        ]
      ]
    }
    

    Demo

    From here, decide what your (valid) target structure should look like, and, if needed, ask another question based on that.


    Edit 1: Your approach using group_by relies on the premise that each input object consists of just one key. If you want to pursue that approach, create objects with each first of a group's first key:

    jq -sc 'group_by(keys_unsorted[])[] | {(.[0] | keys_unsorted[]): [.[][]]}'
    
    {"london":[["x",0],["y",97]]}
    {"paris":[["x",15],["y",8]]}
    

    Demo


    Edit 2: Your original filter can be simplified to {(.city): (.zoo[] | [.room.name, .gpu.sum])} (Demo), which then can be concatenated with this post's first approach by replacing inputs with the above (Demo), which in turn can be simplified (quite similarly to the previous simplification) by not generating objects to just destructure them again, but by directly operating on the original input data instead:

    jq -c '{(.city): .zoo | map([.room.name, .gpu.sum])}'
    
    {"london":[["x",0],["y",97]]}
    {"paris":[["x",15],["y",8]]}
    

    Demo