'jq wildcard as object in getpath split

Given a basic json

{ 
    "notKnown": { 
        "alpha" : {
            "hello":"world"
        }
    } 
}

and then using getpath with a wildcard as an object does not seem to work

//Eg 1 - complete string generates correct result
myPath="notKnown.alpha.hello"
output=$(jq -r --arg str "${myPath}" 'getpath($str|split("."))' <<<$myJson) 
>> output="world"   

//Eg 2 - test the wildcard directly generates correct result
output=$(jq -r '.notKnown[].hello' <<<$myJson) 
>> output="world"

//Eg 3 - merge the wildcard into the formatting from Eg1 - generates null
myPath="notKnown[].hello"
output=$(jq -r --arg str "${myPath}" 'getpath($str|split("."))' <<<$myJson) 
>> output=null

//Eg 4 - merge the wildcard into the formatting from Eg1 - generates null
different example strings that generate null (assuming the first dot should not be used)
 myPath="[].alpha.hello"
 myPath=".[].alpha.hello" //leading dot expect fail
 myPath="[]alpha.hello"
 myPath=".[]alpha.hello"   //leading dot expect fail 

output=$(jq -r --arg str "${myPath}" 'getpath($str|split("."))' <<<$myJson)
>> output=null

Is there a way to have the format in myPath accept the wildcard as an object in the passed $str path?

jq


Solution 1:[1]

getpath doesn't take some query, but a list of keys.

You are effectively calling

getpath( [ "notKnown[]", "hello" ] )

This is equivalent to

.[ "notKnown[]" ][ "hello" ]

You could use

def _simple_query( $q ):
   if $q | length == 0 then
      .
   else
      $q[0] as $key |
      $q[1:] as $r |
      if $key == "*" then
         .[] | _simple_query( $r )
      else
         select( has( $key ) ) | .[ $key ] | _simple_query( $r )
      end
   end;

def simple_query( $q ):
   _simple_query( $q | split(".") );

simple_query( "*.alpha.hello" )

Demo on jqplay

Solution 2:[2]

is there a way to have the format in myPath accept the wildcard as an object in the passed $str path?

Don't think there is a way to let getPath deal with filters like .[].alpha.hello


However, you can use the myPath variable as the raw filter itself to get the desired output:

$ myPath=".[].alpha.hello"
$ jq -r --arg str "${myPath}" "$myPath" json.json
world

Solution 3:[3]

Undeleting this due to @Peak's comment


getpath expects an array with just the keys, so we'll need the following to find the value:

getpath([ "notKnown", "alpha", "hello"  ])

So to get that using an arg, we can use your split command, but we'll need to remove the . and [] from the myPath var:

myPath="notKnown.alpha.hello"
jq -r --arg str "${myPath}" 'getpath($str|split("."))' json.json

Local shell demo:

$ jq . json.json
{
  "notKnown": {
    "alpha": {
      "hello": "world"
    }
  }
}
$
$ myPath="notKnown.alpha.hello"
$
$ jq -r --arg str "${myPath}" 'getpath($str|split("."))' json.json
world
$

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ikegami
Solution 2 0stone0
Solution 3