Use jq to extract a subset of a nested object's fields?

I have a 26MB JSON file containing UN/LOCODE data that I want to restructure and remove some data from so that it takes less space in my app’s binary package.

The JSON contains an array of objects like this:

{
    "Change": null,
    "Coordinates": "4234N 00135E",
    "Country": "AD",
    "Date": "0307",
    "Function": "--3-----",
    "IATA": null,
    "Location": "CAN",
    "Name": "Canillo",
    "NameWoDiacritics": "Canillo",
    "Remarks": null,
    "Status": "RL",
    "Subdivision": null
}

The desired structure is an object rather than an array, keyed on the concatenation of the Country and Location fields, but the only nested fields that I am interested in are "Name" and "Coordinates".

I have been able to accomplish the first step with:

jq 'INDEX("\(.Country)-\(.Location)")'

giving me:

{
    "AD-CAN": {
        "Change": null,
        "Coordinates": "4234N 00135E",
        "Country": "AD",
        "Date": "0307",
        "Function": "--3-----",
        "IATA": null,
        "Location": "CAN",
        "Name": "Canillo",
        "NameWoDiacritics": "Canillo",
        "Remarks": null,
        "Status": "RL",
        "Subdivision": null
   },
   ...
}

but I cannot figure out how to get only the desired keys from the nested objects inside the new top-level object.

If this can’t be done with jq I’ll have to resort to a custom script to do it.

>Solution :

Just reshape the objects using map_values:

jq 'INDEX("\(.Country)-\(.Location)") | map_values({Name, Coordinates})'

Or do it all in one go using reduce:

jq 'reduce .[] as $i ({}; ."\($i.Country)-\($i.Location)" = ($i|{Name, Coordinates}))'

Leave a Reply