Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to use jq reduce to sort array into an object

I am trying to reduce an array

  [
  {"cat": "low", "value": "1"},
  {"cat": "med", "value": "2"},
  {"cat": "med", "value": "3"}
  ]

such that it produces this output:

{
  "low": [
    {
      "cat": "low",
      "value": "1"
    }
  ],
  "med": [
    {
      "cat": "med",
      "value": "2"
    },
    {
      "cat": "med",
      "value": "3"
    }
  ]
}

jq code

I tried this jq code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

reduce .[] as $curr ({}; 
                     $curr.cat as $category |                         # store the current category, eg "low"
                     .[$category] as $currArray |                     # store the current array that eg "low" points to
                     $currArray + [($curr)] as $newCategoryArray |    # add the current object to the current array
                     . + {($category): ($newCategoryArray)}           # use object addition to update the accumulator
                    )

Error

however I am getting the error

jq: error (at <stdin>:5): array ([{"cat":"me...) and object ({"low":[{"c...) cannot be added
exit status 5

Any help is appreciated.

jq snippet here: https://jqplay.org/s/HL0r2CqewAr

Notes:

If possible, could someone also explain why my reducer is throwing the error. I have simplified my problem so an explanation would help me greatly.

Removing an item from the input array, jq is able to run successfully.

The error is only encountered when the ‘category’ is not unique.
enter image description here

>Solution :

With reduce, add the items to and as an array:

jq 'reduce .[] as $curr ({}; .[$curr.cat] += [$curr])'

Demo

Alternatively, you can use group_by, then add the mapped items:

jq 'group_by(.cat) | map({(first.cat): .}) | add'

Demo

The same can be achieved using with_entries:

jq 'group_by(.cat) | with_entries(.key = .value[0].cat)'

Demo

Or even shorter, using INDEX:

jq 'group_by(.cat) | INDEX(first.cat)'

Demo

{
  "low": [
    {
      "cat": "low",
      "value": "1"
    }
  ],
  "med": [
    {
      "cat": "med",
      "value": "2"
    },
    {
      "cat": "med",
      "value": "3"
    }
  ]
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading