Checking for object existence in a deeply nested object

1,613 views
Skip to first unread message

dco...@gaikai.com

unread,
Nov 14, 2018, 10:20:48 PM11/14/18
to Jsonnet

I have a JSON file that may or may not contain a deeply nested key host.provided.default.ip:

{
  "host": {
    "provided": {
      "default": {
        "ip": "192.168.0.1"
      }
    }
  }
}

I’d like to return a default value if that key is not defined. One approach would be to use std.objectHas but this gets messy with deeply nested objects:

if std.objectHas(host, "provided") && std.objectHas(host.provided, "default") && std.objectHas(host.provided.default, "ip") then host.provided.default.ip else "127.0.0.1"

Is there a better way of doing this? I tried std.objectHas(host, "provided.default.ip") but this always returns false.

Thanks!

Preston Podaril

unread,
Nov 15, 2018, 1:16:44 PM11/15/18
to Jsonnet
This is the way to do it, you can't do your second example because this is checking for a key called "provided.default.ip" (aka { host: { "provided.default.ip": ..., } }

you could use a different syntax though, maybe you find this more readable?

if "provided" in host && "default" in host.provided && "ip" in host.provided.default then
  .....

dco...@gaikai.com

unread,
Nov 15, 2018, 1:33:02 PM11/15/18
to Jsonnet

On Thursday, November 15, 2018 at 10:16:44 AM UTC-8, Preston Podaril wrote:

This is the way to do it, you can't do your second example because this is checking for a key called "provided.default.ip" (aka { host: { "provided.default.ip": ..., } }

Good to know. I was wondering if that was what was happening.

I wonder how hard it would be to write a utility function that walks the keys (assuming that keys never contain a . )

you could use a different syntax though, maybe you find this more readable?

if "provided" in host && "default" in host.provided && "ip" in host.provided.default then
  .....

Thanks! That’s definitely a lot nicer on the eyes.

Message has been deleted

dco...@gaikai.com

unread,
Nov 15, 2018, 2:27:48 PM11/15/18
to Jsonnet

On Thursday, November 15, 2018 at 10:33:02 AM UTC-8, dco…@gaikai.com wrote:

I wonder how hard it would be to write a utility function that walks the keys (assuming that keys never contain a . )

I came up with the following utility function for this:

{
    objectHasDeep(o, f)::

        local objectHasDeep_(o, ks) =
            if ! std.objectHas(o, ks[0]) then
                false
            else if std.length(ks) == 1 then
                true
            else
                objectHasDeep_(o[ks[0]], ks[1:]);

        objectHasDeep_(o, std.split(f, '.')),

}

In my case, it’s more useful for a get style function (e.g. objectGetDeep(host, "provided.default.ip", "127.0.0.1")):

{
    objectGetDeep(o, f, default)::

        local objectGetDeep_(o, ks) =
            if ! std.objectHas(o, ks[0]) then
                default
            else if std.length(ks) == 1 then
                o[ks[0]]
            else
                objectGetDeep_(o[ks[0]], ks[1:]);

        objectGetDeep_(o, std.split(f, '.')),
}

Dan Compton

unread,
Jan 14, 2019, 10:43:50 AM1/14/19
to Jsonnet

// Returns true if a value exists at specified path and
// false otherwise
objectHasAtPath(obj, path)::
assert std.isObject(obj) == true;
assert std.isArray(path) == true;
if std.length(path) <= 0 then
false
else if std.length(path) == 1 then
std.objectHas(obj, path[0])
else
if !std.objectHas(obj, path[0]) then
false
else
zstd.objectHasAtPath(obj[path[0]], path[1:]) tailstrict,

// Returns value at path or default, if path does not
// exist in the specified obj.
objectValueAtPath(obj, path, default=null)::
assert std.isObject(obj) == true;
assert std.isArray(path) == true;
if std.length(path) <= 0 then
default
else if std.length(path) == 1 then
if std.objectHas(obj, path[0]) then
obj[path[0]]
else
default
else
if !std.objectHas(obj, path[0]) then
default
else
zstd.objectValueAtPath(obj[path[0]], path[1:], default) tailstrict,

Reply all
Reply to author
Forward
0 new messages