Home > Mobile >  jq get value or default if nested key not present
jq get value or default if nested key not present

Time:12-16

I would like to make a small jq-like function that does get-or-default-if-not-present similar to Python's dict.get(key, default). This is the desired behavior:

% echo '{"nested": {"key": "value", "tricky": null}}' > file.json

% my-jq nested.key \"default\" file.json
"value"
% my-jq nested.tricky \"default\" file.json
null
% my-jq nested.dne \"default\" file.json
"default"

I have tried playing with this answer to a similar question but it doesn't work for nested keys. Does anyone have a suggestion?

function my-jq () {                                                         
  jq --arg key "$1" --arg default "$2" \
  'if has($key) then .[$key] else $default | fromjson end' "$3"
}

CodePudding user response:

You can't use a dotted path as a sequence of keys. You can turn such a path into a valid path for use with the getpath function, however. (There may be a cleaner, more robust way to do this.) The // operator provides for an alternate value should the left-hand side produce false or null.

$ jq  'getpath($key | ltrimstr(".") | split(".")) // $default' file.json --arg key .nested.key --arg default foobar
"value"
$ jq  'getpath($key | ltrimstr(".") | split(".")) // $default' file.json --arg key .nested.dne --arg default foobar
"foobar"

$key | ltrimstr(".") | split(".") first gets rid of the leading ., then splits the remaining string on the remaining . to produce a list of separate keys. getpath produces a filter using that list of keys; getpath(["nested", "key"]) is equivalent (AFAIK) to .nested.key.

CodePudding user response:

Your requirements go against JSON's grain a bit, but here is one possible solution, or the basis of a family of solutions.

This particular solution assumes that the path is given in array form:

function my-jq () {
  jq -c --argjson key "$1" --arg default "$2" '
     first(tostream | select(length == 2 and .[0] == $key)) // null
     | if . then .[1] else $default end
  ' 
}

Examples:

echo '{"nested": {"key": "value", "tricky": null}}' | my-jq2 '["nested","key"]' haha
"value"

echo '{"nested": {"key": "value", "tricky": null}}' | my-jq2 '["nested","nokey"]' haha
"haha"

echo '{"nested": {"key": "value", "tricky": null}}' | my-jq2 '["nested","tricky"]' haha
null
  • Related