console.log
console.log

Reputation: 184

Using jq to convert object to key with values

I have been playing around with jq to format a json file but I am having some issues trying to solve a particular transformation. Given a test.json file in this format:

[
 {
  "name": "A", // This would be the first key
  "number": 1,
  "type": "apple",
  "city": "NYC" // This would be the second key

 },
 {
  "name": "A",
  "number": "5",
  "type": "apple",
  "city": "LA"
 },
 {
  "name": "A",
  "number": 2,
  "type": "apple",
  "city": "NYC"
 },
 {
  "name": "B",
  "number": 3,
  "type": "apple",
  "city": "NYC"
 }
]

I was wondering, how can I format it this way using jq?

[
  {
    "key": "A",
    "values": [
      {
        "key": "NYC",
        "values": [
          {
            "number": 1,
            "type": "a"
          },
          {
            "number": 2,
            "type": "b"
          }
          ]
      },
      {
        "key": "LA",
        "values": [
          {
            "number": 5,
            "type": "b"
          }
        ]
      }
    ]
  },
  {
    "key": "B",
    "values": [
      {
        "key": "NYC",
        "values": [
          {
            "number": 3,
            "type": "apple"
          }
        ]
      }
    ]
  }
]

I have followed this thread Using jq, convert array of name/value pairs to object with named keys and tried to group the json using this expression

jq '. | group_by(.name) | group_by(.city) ' ./test.json

but I have not been able to add the keys in the output.

Upvotes: 2

Views: 427

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134621

You'll want to group the items at the different levels and building out your result objects as you want.

group_by(.name) | map({
    key: .[0].name,
    values: (group_by(.city) | map({
        key: .[0].city,
        values: map({number,type})
    }))
})

Just keep in mind that group_by/1 yields groups in a sorted order. You'll probably want an implementation that preserves that order.

def group_by_unsorted(key_selector):
    reduce .[] as $i ({};
        .["\($i|key_selector)"] += [$i]
    )|[.[]];

Upvotes: 1

Related Questions