Determining if a Key is in a JSON Object - Not Working As Expected


#1

According to https://stackoverflow.com/questions/20804163/check-if-a-key-exists-inside-a-json-object :

myJsonObject.hasOwnProperty('somekey') 
will tell you if myJsonObject has that key itself

myJsonObject["somekey"] will return false if the key does not exist, 
or if its value evaluates to false for any reason

Both of these are returning errors if “somekey” is not a key in my json object. Eg:

server.log("JSON: " + myJsonObject); // JSON: {"error": "stalled"}
if( myJsonObject.hasOwnProperty("rpms") ) // error, won't compile
if( myJsonObject["rpms"] == false ) // compiles, throws error at runtime

What I’m trying to do:

When an IMP sends data to the server, I’d like to reply to the imp with either an error message or a reading, so options would be {“error”: “stalled”} or {“rpms”: 3000}

I had an idea for a workaround that would involve adding a “status_type” key, so it would be like {“status”: 0, “error”: “stalled”} or {“status”: 1, “rpms”: 3000} but later down the road I’d like to have more complicated scenarios that may have a list of optional pieces of information I’m trying to send to the imp, and I don’t want a status code for every possible combination


#2

If you’re exchanging data between the device and the agent, you don’t need to use JSON, which is a serialised string of objects that you can define in squirrel. Just pass the object directly.

In your device, you can use:

agent.send("myData",{ result=100 })

agent.on("myResponse",function(response) {
    if ("error" in response)
         server.log("Error:"+response.error)  // table.key syntax works
    else
        server.log("RPMS"+response["rpms"])  // table["key"] syntax works too
})

and in your agent you can use:

device.on("myData",function(response){
    if ("result" in response)    // use "in" to test for presence of field within table
        device.send("myResponse",{ rpms=3000 })
    else 
        device.send("myResponse",{ error="stalled" })
})

#3

To clarify, Squirrel and the imp API lack the JavaScript .hasOwnProperty() method. Instead, you use the in keyword as demonstrated by @coverdriven’s code:

if ("rpms" in myJsonObject) { . . . }

Note that that syntax assumes rpms is a string — Squirrel table keys need not be, but for non-strings you use this syntax:

if (myJsonObject[false] == "negative") { . . . }

You can use the same with strings, as you do in your // compiles, throws error at runtime line:

if (myJsonObject["rpms"] == 42 ) { . . . }

However, yours is failing because, in Squirrel, a missing key returns null not false.

To summarize, use

if (!("rpms" in myJsonObject)) { server.log("Key 'rpms' missing"); }

#4

@smittytone,
Squirrel isn’t like Javascript in this respect:

if (myJsonObject["rpms"] == null) { server.log("Key 'rpms' missing"); }

indexing a table with a nonexistent key always raises an exception. The only way to safely test it is with “in”

and I think you meant:

if (myJsonObject[false] == "negative") { . . . }

in your second example


#5

Good point, @coverdriven. I was sure I’d used that in code in the past, but you’re right, it fails. Comment amended accordingly.