Bishop Minter
Bishop Minter

Reputation: 107

How do I use jq to single out a specific element in a json array whose order keeps changing?

I have a file with the following format:

{

   "files":[
      {
         "BLOCK1":{
            "SUBBLOCK1":{
               "akey1":"avalue1",
               "bkey1":"bvalue1",
               "ckey1":"cvalue1"
            },
            "dkey1":"dvalue1",
            "key":"evalue1"
         }
      },
      {
         "BLOCK-2":{
            "SUBBLOCK2":{
               "akey2":"avalue2",
               "bkey2":"bvalue2"
            },
            "ckey2":"cvalue2",
            "key":"dvalue2"
         }
      },
      {
         "BLOCK-A":{
            "SUBBLOCKA":{
               "akeyA":"avalueA",
               "bkeyA":"bvalueA"
            },
            "ckeyA":"cvalueA",
            "key":"dvalueA"
         }
      }],
   "NOBLOCK":"value",
   "key":"NOBLOCKvalue"
}

I'm using the following the jq statement to isolate "bvalueA":

value=$(jq -r '.files | .[2] | .["BLOCK-A"].SUBBLOCKA.bkeyA' jqtest)

Which works just fine. But the file changes order every night. So BLOCK-A might be element 0 one night, 1 the next, so on and so forth. How can I modify jq to always drill down to BLOCK-A no matter which element in the array it is?

Upvotes: 0

Views: 536

Answers (4)

peak
peak

Reputation: 116780

This might be the least-keystrokes solution:

 .files[]."BLOCK-A"//empty|.SUBBLOCKA.bkeyA

If there is a possibility that there is more than one "BLOCK-A" element, and if you want to ensure that all but the first will be ignored when that is the case, then you could wrap the above in a call to first/1, assuming your version of jq has it: first( ... )

Using first in this manner also yields a more efficient solution.

Upvotes: 2

jq170727
jq170727

Reputation: 14665

Here is an solution based on my previous answer to your earlier question:

$ jq -M '

def getfile($k): .files[] | select(keys[] == $k) | .[$k];

getfile("BLOCK-A").SUBBLOCKA.bkeyA

' jqtest

With the sample data provided the output is:

"bvalueA"

Upvotes: 0

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

The alternative approach with has() function:

jq -r '.files[] | if (has("BLOCK-A")) then .["BLOCK-A"].SUBBLOCKA.bkeyA else empty end' jqtest
bvalueA

Upvotes: 0

hek2mgl
hek2mgl

Reputation: 158060

You are looking for select():

jq -r '.files[]|select(.["BLOCK-A"])|.["BLOCK-A"].SUBBLOCKA.bkeyA'

or map():

jq -r '.files|map(.["BLOCK-A"]//empty)[].SUBBLOCKA.bkeyA'

Upvotes: 1

Related Questions