Notehub has long relied on JSONata 1.5.4 to allow users to transform event data before it's routed to their cloud endpoint of choice. Today we're rolling out JSONata 2.0.6 in Notehub, bringing modern operators, streamlined transforms, and powerful new functions straight into your workflows.
What is JSONata
JSONata is an expression language that lets you query,
transform, and enhance JSON - using a syntax that is recognizable to C and
JavaScript developers. Open-sourced in
2016 by IBM's Andrew Coleman, JSONata set out to give JSON the same first-class
transformation tooling that XPath/XQuery gave XML. Instead of spinning up a
Lambda function to process JSON and jumping through JSON.parse
hoops, a simple
JSONata expression can turn a bulky JSON payload into concise output.
Today, JSONata underpins data flows in Node-RED, AWS Step Functions, serverless backends, and a growing list of IoT platforms like Blues Notehub.
Using JSONata in Notehub
Blues allows developers to utilize JSONata expressions inside
Notehub Routes. After
a Notecard syncs an event with Notehub, and before it is routed out of
Notehub, you can attach a JSONata expression to trim fields, re-nest objects,
perform calculations, or even block routing on an event-by-event basis with
Notehub-specific helper functions
like $doNotRoute()
.
Read more about using JSONata in Notehub in our guide on Using JSONata to Transform JSON.
For example, here is a full unprocessed event from a Blues Notecard:
{
"event": "77e21f12-54c6-4114-afa0-e3ff7cdc2b57",
"file": "data.qo",
"body": {
"temp": "23.1",
"humidity": "64",
"aqi": 34
},
"session": "105cc330-4f43-41b3-b575-aa744cc22f83",
"transport": "cell:lte:fdd",
"best_id": "dev:860322068073292",
"device": "dev:860322068073292",
"product": "product:com.blues.test",
"app": "app:9a442885-d04d-4f5d-bca5-94eb07f7a27f",
"received": 1745505755.094598,
"req": "note.add",
"best_location_type": "triangulated",
"best_location_when": 1743006603,
"best_lat": 43.06536,
"best_lon": -89.41761,
"best_location": "Madison Wisconsin",
"best_country": "US",
"best_timezone": "America/Chicago",
"tower_when": 1742848243,
"tower_lat": 43.072254,
"tower_lon": -89.44577,
"tower_country": "US",
"tower_location": "Madison Wisconsin",
"tower_timezone": "America/Chicago",
"tower_id": "310,410,17169,77315594",
"tri_when": 1743006603,
"tri_lat": 43.06536,
"tri_lon": -89.41761,
"tri_location": "Madison Wisconsin",
"tri_country": "US",
"tri_timezone": "America/Chicago",
"tri_points": 5,
"fleets": [
"fleet:4d7ccbcb-a410-4730-9ee2-b483b3523b17"
]
}
Lots of data to parse through, right? Well, here is a simple one-line JSONata
expression that pulls out just the temp
and location values:
{"temp": body.temp, "lat": best_lat, "lon": best_lon}
This provides the cloud service to which you're routing data only the data elements it requires:
{
"temp": "23.1",
"lat": 43.06536,
"lon": -89.41761
}
JSONata: What's New Since 1.5.4
2.0.6 itself adds no new language features except for the ability to support parsing of binary, octal, and hexadecimal numbers. No breaking changes were made to the JSONata language itself.
However, everything introduced in the 1.6-1.8 JSONata releases is now available in Notehub:
- Parent operator
%
and position operator#
$single
,$error
,$assert
,$encodeUrl
,$distinct
$type
for quick type introspection
TIP: You can experiment with JSONata expressions in the browser using the JSONata Exerciser.
For example, let's use some of these new JSONata functions in the same Notecard event used previously. The following JSONata expression is fully compatible with JSONata 2.0.6:
{
"id": device,
"product": product,
"metrics": {
"temp_c": $number(body.temp),
"temp_f": $eval($string($number(body.temp)) & "*9/5+32"),
"humidity_pct": $parseInteger(body.humidity, "0"),
"aqi": body.aqi
},
/* Uses # (position) and % (parent) */
"fleets_checked": fleets#$i.{
"pos": $i,
"raw": $,
"from_parent_product": %.product
},
/* Uses $encodeUrlComponent (part of $encodeUrl) */
"geo": {
"lat": best_lat,
"lon": best_lon,
"label": best_location,
"map_url":
"https://maps.google.com/?q=" & best_lat & "," & best_lon &
"&label=" & $encodeUrlComponent(best_location)
},
/* Uses $distinct */
"countries_seen": $distinct([best_country, tower_country, tri_country]),
/* Uses $assert and $type for type introspection */
"assertions": [
$assert($type(body.aqi) = "number", "body.aqi must be numeric"),
$assert($type(body.humidity) = "string", "body.humidity must be a string")
],
"transport_checked":
$substring(transport, 0, 5) = "cell:" ? true : $error("unexpected transport: " & transport),
"debug_types": {
"body.temp": $type(body.temp),
"body.humidity": $type(body.humidity),
"body.aqi": $type(body.aqi),
"received": $type(received)
}
}
This expression provides us with the following JSON output:
{
"id": "dev:860322068073292",
"product": "product:com.blues.test",
"metrics": {
"temp_c": 23.1,
"temp_f": 73.58,
"humidity_pct": 64,
"aqi": 34
},
"fleets_checked": {
"pos": 0,
"raw": "fleet:4d7ccbcb-a410-4730-9ee2-b483b3523b17",
"from_parent_product": "product:com.blues.test"
},
"geo": {
"lat": 43.06536,
"lon": -89.41761,
"label": "Madison Wisconsin",
"map_url": "https://maps.google.com/?q=43.06536,-89.41761&label=Madison%20Wisconsin"
},
"countries_seen": [
"US"
],
"assertions": [],
"transport_checked": true,
"debug_types": {
"body.temp": "string",
"body.humidity": "string",
"body.aqi": "number",
"received": "number"
}
}
Migrating Existing JSONata Expressions
There is no migration necessary! Again, the good news about this upgrade on Notehub is that your existing JSONata expressions will continue to work perfectly as-is.
If you notice any issues whatsoever, don't hestiate to reach out to us on the Blues Developer Forum.
FYI, the breaking changes introduced in JSONata 2.0 have to do with the JavaScript API, not the language itself.
Looking Forward
JSONata keeps getting faster, safer, and more expressive. If you're already leaning on it to massage your Notecard events in Notehub, the move to 2.0.6 is painless and sets you up for success in the IoT.
Happy Hacking! 💙