Hosted extractor mapping language
The hosted extractor mapping language translates JSON structures to other JSON structures. The language is similar to JavaScript and is purely functional. A mapping is a single expression that describes how to build one JSON structure from another.
Variables
Use these input objects to define a mapping:
-
input
- This is the content of the received message, parsed into an object. -
context
- This contains information about the message. The content of this object varies between the different hosted extractors.For MQTT, the
context
object containstopic
: which topic the message arrived at
For examples of using these variables, see Handling more data in a single message.
When variables are objects or arrays they can be selected from. For example, given the object
{
"someField": 123,
"someArray": [1, 2, 3, { "nested": [1, 2, 3] }]
}
you can select from an object with
input.someField -> 123
or
input["someField"] -> 123
You select from arrays with
input.someArray[0] -> 1
Selectors can be nested as
input.someArray[3].nested[2] -> 3
Selectors can contain expressions
input.someArray[1 + 1] -> 3
Functions
The hosted extractor mapping language contains a set of predefined functions, which can be used to transform the input in other ways.
For example,
float("1.4") -> 1.4
will try to transform the input from a string to a number, which may fail.
Any function can also be called postfix, as a method on a value, so you could instead write
"1.4".float() -> 1.4
This is especially useful when dealing with chained operations.
See also Functions.
Lambda expressions
Some functions can take user defined functions as arguments, such as map
, reduce
, or filter
. To create the functions for these, use Lambda notation: argument => return
.
If the function takes no arguments, use ()
as the input to the function. If a function takes multiple values, denote them as a tuple: (arg1, arg2)
.
Examples
If we want to turn the list [1, 2, 3, 4]
into [2, 4, 6, 8]
we can use map
to apply a function to each member of the list, and write a lambda function that doubles each value:
[1, 2, 3, 4].map(number => number * 2) -> [2, 4, 6, 8]
If you want to remove all null
s from a list, use the filter
function, and write a lambda function that returns true if the value is the null
type using the is
operator:
[0, 1, 2, 3, 4, null, 5].filter(item => !(item is "null")) -> [0, 1, 2, 3, 4, 5]
To sum all the numbers from 1 through 10, use the reduce
function to iteratively add the next member of the list to an aggregate:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, next) => sum + next, 0) -> 110
Operators
The operators take one or two inputs and output some value. The operators are:
Plus
1 + 2 + 3 -> 6
Adds two numbers together.
Minus
1 - 2 - 3 -> -4
Subtracts a number from another.
Multiply
2 * 3 -> 6
Multiplies two numbers.
Divide
3 / 2 -> 1.5
Divides one number by another.
And
true && false -> false
Boolean AND, returns true
if the inputs are both not null
or false
.
Or
true || false -> true
Boolean OR, returns true
if either input is not null
or false
.
Equals
1 == 2 -> false
Checks for exact equality. The inputs must be the same type, or this will be false
.
Not equals
1 != 2 -> true
Checks for inequality.
Greater than
2 > 3 -> false
Checks if the first number is greater than the second number.
Greater than or equal
2 >= 3 -> false
Checks if the first number is greater than or equal to the second number.
Less than
2 < 3 -> true
Checks if the first number is less than the second number.
Less than
2 <= 3 -> true
Checks if the first number is less than or equal to the second number.
Modulo
5 % 2 -> 1
Computes the modulus, or remainder, of the first argument divided by the second argument.
Is
5 is float
This is the type check operator, used to check if the first argument is the type given by the second argument. The valid types are
null
object
array
string
number
float
int
bool
Any float
or int
is also number
.
If expressions
You can use functional-style if
expressions. For example
if 2 > 3 {
"hello"
} else if 2 == 2 {
"world"
} else {
"goodbye"
}
will return "world"
. There is an if
function as well, but using expressions usually results in cleaner code.
Objects
You can create JSON objects with familiar JSON syntax:
{
"hello": 123,
"test": input.something
}
These objects can be accessed, just like input variables:
{ "hello": 123 }.hello
You can concat objects using the ...
operator:
{
"test": 123,
...{
"hello": "world"
},
...{
"world": "hello"
}
}
will yield the object
{
"test": 123,
"hello": "world",
"world": "hello"
}
Object keys can also be expressions:
{ concat("he", "llo"): "world" }
will yield an object
{ "hello": "world" }
Arrays
Arrays can be created using a JSON syntax:
[1, 2, 3]
You can access arrays using brackets, just like with inputs:
[1, 2, 3][0] -> 1
Arrays also support the ...
operator:
[
1,
...[2, 3],
...[4, 5]
]
will yield
[1, 2, 3, 4, 5]