Steve Amerige
Steve Amerige

Reputation: 1499

jq: How to combine disjoint object values as a single object of key/value pairs?

If I have a JSON input data:

input.json

{
   "metadata": {
      "guid": "07f90eed-105d-41b2-bc20-4c20dfb51653"
   },
   "entity": {
      "name": "first"
   }
}
{
   "metadata": {
      "guid": "da187e3a-8db9-49fd-8c05-41f29cf87f51"
   },
   "entity": {
      "name": "second"
   }
}
{
   "metadata": {
      "guid": "6685c3af-5427-4add-8764-7b18ae3c23bb"
   },
   "entity": {
      "name": "third"
   }
}

and I want to create from it the following:

{
  "first": "07f90eed-105d-41b2-bc20-4c20dfb51653",
  "second": "da187e3a-8db9-49fd-8c05-41f29cf87f51",
  "third": "6685c3af-5427-4add-8764-7b18ae3c23bb"
}

That is, the input data is a collection of separate JSON objects, each of which has the structure shown. I want the output to be a single JSON object where the key is the .entity.name and the value is the .metadata.guid.

I have tried:

jq -r '{.entity.name: .metadata.guid}' input.json
jq -r 'map({(.entity.name): .metadata.guid})' input.json

but these just yields a syntax error. The closest I got was:

jq -r '.entity.name as $name|.metadata.guid as $guid | { ($name) : ($guid) }' input.json
{
  "first": "07f90eed-105d-41b2-bc20-4c20dfb51653"
}
{
  "second": "da187e3a-8db9-49fd-8c05-41f29cf87f51"
}
{
  "third": "6685c3af-5427-4add-8764-7b18ae3c23bb"
}

But, the there are still 3 objects (not 1).

I did get one form to give me what I want, but I suspect there is an easier way to do this:

jq -r '.entity.name as $name|.metadata.guid as $guid | { ($name) : ($guid) }' input.json | jq -s add
{
  "first": "07f90eed-105d-41b2-bc20-4c20dfb51653",
  "second": "da187e3a-8db9-49fd-8c05-41f29cf87f51",
  "third": "6685c3af-5427-4add-8764-7b18ae3c23bb"
}

Any thoughts how how to do this properly?

Upvotes: 3

Views: 1550

Answers (2)

RomanPerekhrest
RomanPerekhrest

Reputation: 92884

With single jq command:

jq -s '[.[] | { (.entity.name): .metadata.guid }] | add' input.json
  • -s (--slurp) - instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once.

The output:

{
  "first": "07f90eed-105d-41b2-bc20-4c20dfb51653",
  "second": "da187e3a-8db9-49fd-8c05-41f29cf87f51",
  "third": "6685c3af-5427-4add-8764-7b18ae3c23bb"
}

Upvotes: 7

axiac
axiac

Reputation: 72336

A simpler way to get three objects is jq '{(.entity.name): .metadata.guid}' input.json.

Wrapping the key (.entity.name) into parentheses tells jq to evaluate it as an expression, not as a string.

This leads to a simpler form of what you already have (using two invocations of jq):

$ jq '{(.entity.name): .metadata.guid}' input.json | jq -s add
{
  "first": "07f90eed-105d-41b2-bc20-4c20dfb51653",
  "second": "da187e3a-8db9-49fd-8c05-41f29cf87f51",
  "third": "6685c3af-5427-4add-8764-7b18ae3c23bb"
}

Upvotes: 2

Related Questions