Access object value using position not name

My JSON/JSONata-fu has gone missing :frowning:
If I've got a msg.payload object

{
  "uuid":"fd8916521157",
  "characteristics":
    {
      "notification":true,
      "e95d9250251d470aa062fa1922dfa9a8":23
    }
}

Can I access the 23 value without having to specify the e95d9250251d470aa062fa1922dfa9a8 key name?

e.g .don't want to use

msg.payload.characteristics.e95d9250251d470aa062fa1922dfa9a8

I just want to reference it as 2nd item of 2nd item of msg.payload

or happy with 2nd item of msg.payload.characteristics

var key = Object.keys(your-object-here)[your-index-here];
var value = your-object-here[key]

But what if the object has your key at different index ....

1 Like

Is the key always a hexadecimal string with a similar length? It looks to me like you're working with Bluetooth or something similar where those keys are having specifications. For example hexadecimal with length X. If that's the case, you can set up a filter for the keys to only allow through keys that match the pattern.

For example: http://try.jsonata.org/ryG3Qpopr

payload.characteristics.$sift(function ($val, $key) {$key ~> /[a-f0-9]{32}/}).*

That gets to payload.characteristics, then uses the $sift function to get out only the object properties matching the key regex. The key here is defined as "valid characters for hexadecimal, exactly 32 of them". If you'd like to play/experiment with variations, see the following example too: https://regex101.com/r/03JW3B/1
Finally, the .* part gets the value out.

1 Like

I went and had some lunch and come back refreshed and came up with this

$spread(payload.characteristics)[1].*

(splits the characteristics object into an array - pick 2nd item then return its payload

Thanks to Lena for the .* info :slight_smile:

Still open to any shorter methods :slight_smile:

PS - yes it is bluetooth info

One should keep in mind that the order of object properties is not defined. Relying on that will likely lead to errors.

2 Likes

If it's bluetooth, then hexadecimal 32 is a constant. Meaning that every of those keys will look like that. I know regex is occasionally asking for more problems than you started out with, but unless you're going to have multiple keys with this kind of uuid on the object, the solution I posted above will be stable and won't run into trouble if through an update or anything else the key stops being on the second position. Keep in mind that keys on objects are unsorted in basis, and could pop up anywhere in terms of position. Order of objects in arrays is pretty constant when you don't touch them, order of keys on objects is not.

2 Likes

I agree with Lena. In this context, using a regexp to find the hex-like key would be the best solution. :slightly_smiling_face:

But using something like that as an object property is a bad design choice for a data structure in the first place. Not very user-friendly. :see_no_evil:

Firm agree, welcome to the Bluetooth specifications... Bluetooth Core Specifications 5.1, GATT specifically: https://www.bluetooth.com/specifications/gatt/

Usually that property refers to a constant that's documented somewhere in a local specification for the device you are using, but if you're building something less official you have to come up with those properties for yourself. Or if you're reverse engineering a device it gets even worse... I put together a bluetooth connector between a pycom wipy and my phone for gps tracking on the go as a test. I definitely needed that specification file. Same for when I was reverse engineering a toothbrush (don't ask, they nowadays come with bluetooth and an app to film your mouth, I was trying to see if there was something useful inside I could mayhaps use)