jq

Merging array of objects based on values in JQ


I've created a JSON array that contains objects I want group and nest based on a shared value, and then have an array with a list of matching values under this. I just can't figure it out.

Here is my input data:

[
  {
    "name": "pcmp-ingestion-master",
    "s2iVersion": "4.5.0-05",
    "muleVersion": "4.5.0",
    "imageSha": "sha256:c1b618c6fbec2e2832824578a47893707ebea8a681bab1ce97b73b1a1e2fccb5"
  },
  {
    "name": "pcmp-ingestion-syst",
    "s2iVersion": "4.4.0-87",
    "muleVersion": "4.4.0",
    "imageSha": "sha256:c1b618c6fbec2e2832824578a47893707ebea8a681bab1ce97b73b1a1e2fccb5"
  },
  {
    "name": "pcmp-ingestion-uat",
    "s2iVersion": "4.4.0-87",
    "muleVersion": "4.4.0",
    "imageSha": "sha256:c1b618c6fbec2e2832824578a47893707ebea8a681bab1ce97b73b1a1e2fccb5"
  },
  {
    "name": "qualityofhire-uat",
    "s2iVersion": "4.4.0-85",
    "muleVersion": "4.4.0",
    "imageSha": "sha256:baabd127862667b17bda7ff278144314469205c12d1445295dc3cf0001ac79db"
  },
  {
    "name": "virtual-assist-uat",
    "s2iVersion": "4.4.0-85",
    "muleVersion": "4.4.0",
    "imageSha": "sha256:b82d58aa174fe668061e41453d11212e9162381f8b20a2db3b9a525e6b981140"
  }
]

Here is what I'd ultimately like to have as an output from JQ.

[
  {
    "muleVersion": "4.4.0",
    "s2iVersions": [
      "4.4.0-87",
      "4.4.0-85"
    ]
  },
  {
    "muleVersion": "4.6.0",
    "s2iVersions": [
      "4.6.0-01"
    ]
  }
]

I've tried a few things but can only mange to map these down flat and select unique values, without combining them, like so:

map( { muleVersion: .muleVersion, "s2iVersions": ([.s2iVersion])}) | unique_by(.s2iVersions)

Which gives this output

[
  {
    "muleVersion": "4.4.0",
    "s2iVersions": [
      "4.4.0-85"
    ]
  },
  {
    "muleVersion": "4.4.0",
    "s2iVersions": [
      "4.4.0-87"
    ]
  },
  {
    "muleVersion": "4.6.0",
    "s2iVersions": [
      "4.6.0-01"
    ]
  }
]

I feel like the solution to this is probably blindingly obvious, but I'm in a rut. Does anyone have any pointers?


Solution

  • Use group_by/1, map and unique

    group_by(.muleVersion) | 
      map({"muleVersion": .[0].muleVersion, s2iVersions: (map(.s2iVersion) | unique)})