Search code examples
jsonselectjqdefaultkey-value

How to use fallback value when jq select() returns false


Let's say I have a JSON array like this:

[
    {
        "name": "alpha",
        "value": 1
    },
    {
        "name": "beta",
        "value": 2
    },
    ...
]

(It contains about 50-100 items; this is a simplified example.)

I want to produce a JSON object from it like this:

{
  "alpha": 1,
  "beta" 2,
  ...
}

I think the jq filter for it looks something like this:

.[] | { 
  "alpha": select(.name == "alpha") | .value,
  "beta": select(.name == "beta") | .value,
  ...
}

That doesn't actually work when I try it on https://jqplay.org/s/SOKd4oCh2k, but I think it's pretty close.

OK now here's the tricky part: sometimes the object with "name": "alpha" (or "name": "beta", etc.) won't actually exist in the input array! In that case, I want to print "alpha": null or "alpha": "". But I can't figure out how to integrate that into my select() call.

In practice I need this to scrape job metrics from a batch scheduling system, where I'm changing the metrics over time as I run performance tests, so any given metric that I'm querying might not exist for a particular job run, but I still want to see all the other metrics from that job run.


Solution

  • The jq-esque solution to the problem is illustrated by:

    jq 'from_entries | {alpha, beta, gamma}' input.json
    

    This will convert the array to an object, and then select the values corresponding to the specified keys if present, while also ensuring all the specified keys are present.

    Keylist

    If you have a JSON array of key namess (say $keylist), you could write:

    from_entries as $in
    | reduce $keylist[] as $key ({}; .[$key]=$in[$key])
    
    

    Fallback value

    Or if you want to specify your own fallback value, say $default:

    from_entries as $in
    | reduce $keylist[] as $key ({}; .[$key] = $in[$key] // $default)
    
    

    or perhaps (depending on your detailed requirements):

    from_entries as $in
    | reduce $keylist[] as $key ({};
        .[$key] = if ($in | has($key)) then $in[$key] else $default end)