Run JavaScript code in Azure Stream Analytics query
Tags: azure, streamanalytics, udf
Published: 2021-04-01 05:27:28

Azure Stream Analytics has **"User Defined Function** feature, where we can write our own function by using JavaScript.

# Why UDF?

Stream Analytics provides strong built-in functions, such as string function, date time function, aggregate function, etc.

[Built-in Functions](https://docs.microsoft.com/en-us/stream-analytics-query/built-in-functions-azure-stream-analytics)

However, we sometime cannot find out-of-box function we need. That's where UDF comes in to rescue us :)

Let's see some scenario.

# Scenario 1: Input contains JSON payload as string

Many data source, such as IoT Hub or Event Grid send data as JSON format. But it contains string data which is JSON payload as part of input. Example JSON looks like below.

```json
{
  "type":"temperature",
  "temperature":30.2,
  "humidity":42.2,
  "location":"{\"longitude\":139.839478,\"latitude\":35.652832}"
}
```
If I simply upload this as sample input, I see location becomes text data.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qx3o61x5qqm6p3ws7o5j.png)

In this case, we cannot get longitude value by following query.

```sql
SELECT
    location.longitude
INTO
    [YourOutputAlias]
FROM
    [YourInputAlias]
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y0xjhcpxratzjtomhckn.png)

To solve this issue, we can add UDF.

1\. Go to Functions and add new Javascript UDF.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1pkfqx7seupsnnbfe2tw.png)

2\. Add function to parse json string. I named this as "ParseJson".

```javascript
function main(x) {
    return JSON.parse(x);
}
```
3\. Save the function and go back to query. Now we can write query as below.

```sql
SELECT
    UDF.ParseJson(location).longitude
INTO
    [YourOutputAlias]
FROM
    [YourInputAlias]
```

4\. See the result. **UDF.ParseJson(location)** returns JSON object so we can access its property now.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q411zgkgd0zm1at5ogva.png)

# Scenario 2: Use "Max" value of some type

For example, [Azure Table Storage Log Tail Pattern](https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-design-patterns#log-tail-pattern) requires some calculations for datetime field. Azure Stream Analytics has many built-in datetime function, but I cannot find Datetime.MaxValue type of function.

At the end, I cannot find native Javascript datetime maxvalue property, so I use "8640000000000000" by following some of stackoverflow threads. If anyone knows better solution, please teach me :)

So let's use UDF to implement function which returns expected value for log tail pattern.

1\. Add another UDF and enter following script.

```javascript
// Sample UDF which returns sum of two values.
function main(x) {
    var current = new Date(x);
    return (new Date(8640000000000000).getTime() - current)
}
```

2\. Change input sample.

```json
{
    "type":"temperature",
    "temperature":30.2,
    "humidity":42.2,
    "location":"{\"longitude\":139.839478,\"latitude\":35.652832}",
    "timestamp":"Thu Apr 01 2021 14:22:05 GMT+0900"
  },
  {
    "type":"temperature",
    "temperature":30.2,
    "humidity":42.2,
    "location":"{\"longitude\":139.839478,\"latitude\":35.652832}",
    "timestamp":"Thu Apr 01 2021 14:23:05 GMT+0900"
  }
```

3\. Run following query.

```sql
SELECT
    timestamp, 
    UDF.GetInvertedTicks(timestamp),
    UDF.ParseJson(location).longitude
INTO
    [YourOutputAlias]
FROM
    [YourInputAlias]
```

4\. Confirm the result.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1qzmehr0lwfzguzfjhm.png)

# Summary

We can still do our best to write query to get desired result with built-in functions, but it maybe easier to use UDF depending on scenarios :)