Open source Enterprise Grafana Cloud

UQL parser

UQL (Unstructured Query Language) is a query language for transforming and manipulating data from JSON, CSV, XML, and GraphQL sources. Inspired by the Kusto Query Language (KQL), UQL uses a pipeline syntax where commands are joined by |.

Syntax basics:

  • Commands are separated by | (pipe), typically one per line
  • Field names are enclosed in double quotes: "fieldName"
  • String literals use single quotes: 'value'

Note

UQL is in beta. If you encounter issues, report them on GitHub.

Quick example

The following example demonstrates how UQL transforms nested JSON data into a flat table.

Input data:

JSON
[
  {
    "id": 1,
    "name": { "firstName": "john", "lastName": "doe" },
    "dob": "1985-01-01",
    "city": "chennai"
  },
  {
    "id": 2,
    "name": { "firstName": "alice", "lastName": "bob" },
    "dob": "1990-12-31",
    "city": "london"
  }
]

UQL query:

SQL
parse-json
| extend "full name"=strcat("name.firstName",' ',"name.lastName"), "dob"=todatetime("dob")
| project-away "name"
| order by "full name" asc

Output:

iddobcityfull name
21990-12-31londonalice bob
11985-01-01chennaijohn doe

Basic UQL commands

project

Select specific columns to include in the output. Use dot notation to access nested properties. To rename a column, use the syntax "new_name"="source_field".

SQL
parse-json
| project "id", "name.firstName", "date of birth"="dob"

This selects id, the nested name.firstName field, and renames dob to date of birth.

project-away

Remove specific columns from the output. This command only accepts top-level field names — dot notation and aliases are not supported.

SQL
parse-json
| project-away "id", "city"

order by

Sort results by a column in ascending (asc) or descending (desc) order.

SQL
parse-json
| order by "full name" asc

where

Filter rows based on a condition. Only rows where the condition evaluates to true are included.

SQL
parse-json
| where "age" > 18

Combine conditions with and or or:

SQL
parse-json
| where "country" == 'USA' and "age" >= 21

Use in to match against multiple values:

SQL
parse-json
| where "country" in ('USA', 'Canada', 'Mexico')

Use !in to exclude values:

SQL
parse-json
| where "country" !in ('USA', 'Canada')

Supported operators: ==, !=, >, >=, <, <=, in, !in

extend

Add new columns or transform existing columns using functions. Use the syntax "column_name"=function("source_field").

SQL
parse-json
| extend "dob"=todatetime("dob"), "city"=toupper("city")

This converts dob to a datetime and transforms city to uppercase.

The following sections describe the functions available with extend, organized by category.

String functions

FunctionSyntaxDescription
touppertoupper("name")Convert to uppercase
tolowertolower("name")Convert to lowercase
trimtrim("name")Remove whitespace from start and end
trim_starttrim_start("name")Remove whitespace from start
trim_endtrim_end("name")Remove whitespace from end
strlenstrlen("name")Return string length
strcatstrcat("col1","col2")Concatenate two or more columns
substringsubstring("col1",1,5)Extract substring (start index, length)
splitsplit("col1",'delimiter')Split string by delimiter
replace_stringreplace_string("col1",'find','replace')Replace text within a string
reversereverse("col1")Reverse a string
extractextract('regex',index,"col1")Extract using regex (index: 0, 1, …)

Type conversion functions

FunctionSyntaxDescription
tonumbertonumber("age")Convert to number
tostringtostring("age")Convert to string
tointtoint("value")Convert to integer
tolongtolong("value")Convert to long integer
todoubletodouble("value")Convert to double
tofloattofloat("value")Convert to float
tobooltobool("value")Convert to boolean

DateTime functions

FunctionSyntaxDescription
todatetimetodatetime("dob")Convert string to datetime
tounixtimetounixtime("dob")Convert datetime to unix epoch (ms)
format_datetimeformat_datetime("dob",'DD/MM/YYYY')Format datetime as string
add_datetimeadd_datetime("dob",'-1d')Add duration (e.g., -1d, 2h)
unixtime_seconds_todatetimeunixtime_seconds_todatetime("ts")Convert unix seconds to datetime
unixtime_milliseconds_todatetimeunixtime_milliseconds_todatetime("ts")Convert unix milliseconds to datetime
unixtime_microseconds_todatetimeunixtime_microseconds_todatetime("ts")Convert unix microseconds to datetime
unixtime_nanoseconds_todatetimeunixtime_nanoseconds_todatetime("ts")Convert unix nanoseconds to datetime
startofminutestartofminute("dob")Round to start of minute
startofhourstartofhour("dob")Round to start of hour
startofdaystartofday("dob")Round to start of day
startofweekstartofweek("dob")Round to start of week
startofmonthstartofmonth("dob")Round to start of month
startofyearstartofyear("dob")Round to start of year

Math functions

FunctionSyntaxDescription
sumsum("col1","col2")Add two or more columns
diffdiff("col1","col2")Subtract columns (col1 - col2)
mulmul("col1","col2")Multiply columns
divdiv("col1","col2")Divide columns (col1 / col2)
percentagepercentage("col1","col2")Calculate percentage ((col1/col2) × 100)
floorfloor("col1")Round down to nearest integer
ceilceil("col1")Round up to nearest integer
roundround("col1")Round to nearest integer
signsign("col1")Return sign (-1, 0, or 1)
powpow("col1",3)Raise to power
loglog("col1")Natural logarithm
log2log2("col1")Base-2 logarithm
log10log10("col1")Base-10 logarithm
sinsin("col1")Sine
coscos("col1")Cosine
tantan("col1")Tangent

URL functions

FunctionSyntaxDescription
parse_urlparse_url("col1")Parse URL into components
parse_urlparse_url("col1",'pathname')Get URL part: host, hash, origin, href, protocol, pathname, search
parse_urlparse_url("col1",'search','key1')Get query parameter value
parse_urlqueryparse_urlquery("col1",'key1')Parse query string and get value for key

Encoding functions

FunctionSyntaxDescription
atobatob("col1")Decode base64 string
btoabtoa("col1")Encode string to base64

Math functions example

Input data:

JSON
[{ "a": 12, "b": 20 }, { "a": 6, "b": 32 }]

UQL query:

SQL
parse-json
| project "a", "triple"=sum("a","a","a"), "thrice"=mul("a",3), sum("a","b"), diff("a","b"), mul("a","b")

Output:

atriplethricesumdiffmul
12363632-8240
6181838-26192

Chain multiple transformations

To apply multiple transformations to the same field, repeat the field name in the extend command:

SQL
parse-json
| extend "name"=tolower("name"), "name"=trim("name")

This applies tolower first, then trim to the name field.

Array functions

pack

Convert key-value pairs into an object.

SQL
extend "foo"=pack('key1',"value1",'key2',"value2")

Output: {key1: value1, key2: value2}

array_from_entries

Build an array of objects from a list of values.

SQL
extend "foo"=array_from_entries('timestamp',[2010,2020,2030])

Output: [{timestamp: 2010}, {timestamp: 2020}, {timestamp: 2030}]

array_to_map

Convert an array to an object with named keys.

SQL
extend "foo"=array_to_map(['chennai','india'],'city','country')

Output: {city: 'chennai', country: 'india'}

summarize

Aggregate data by grouping on one or more columns. Use the syntax "alias"=function("field") by "group_field".

Aggregation functions

FunctionSyntaxDescription
countcount()Count of rows
sumsum("age")Sum of values
minmin("population")Minimum value
maxmax("foo")Maximum value
meanmean("foo")Average value
firstfirst("foo")First value in group
lastlast("foo")Last value in group
latestlatest("foo")Most recent non-null value
randomrandom("foo")Random value from group
dcountdcount("country")Count of distinct values
distinctdistinct("country")List of distinct values
countifcountif("age", "> 18")Count where condition is true
sumifsumif("salary", "> 1000")Sum where condition is true
minifminif("age", "> 0")Minimum where condition is true
maxifmaxif("score", "!= null")Maximum where condition is true

Summarize example

Input data:

JSON
[
  { "city": "tokyo", "country": "japan", "population": 200 },
  { "city": "newyork", "country": "usa", "population": 60 },
  { "city": "oslo", "country": "usa", "population": 40 },
  { "city": "new delhi", "country": "india", "population": 180 },
  { "city": "mumbai", "country": "india", "population": 150 }
]

UQL query:

SQL
parse-json
| summarize "number of cities"=count(), "total population"=sum("population") by "country"
| extend "country"=toupper("country")
| order by "total population" desc

Output:

countrynumber of citiestotal population
INDIA2330
JAPAN1200
USA2100

pivot

Transform rows into columns. The pivot command accepts three arguments:

  1. Aggregation function — for example, count("id") or sum("salary")
  2. Row field — the field to use for row grouping, for example, "country"
  3. Column field — the field whose values become column headers, for example, "occupation"
Pivot example

Input data (CSV):

csv
name,age,country,occupation,salary
Leanne Graham,38,USA,Devops Engineer,3000
Ervin Howell,27,USA,Software Engineer,2300
Clementine Bauch,17,Canada,Student,
Patricia Lebsack,42,UK,Software Engineer,2800
Leanne Bell,38,USA,Senior Software Engineer,4000
Chelsey Dietrich,32,USA,Software Engineer,3500

UQL query (pivot):

SQL
parse-csv
| extend "salary"=tonumber("salary")
| pivot sum("salary"), "country", "occupation"

Output:

countryDevops EngineerSoftware EngineerStudentSenior Software Engineer
USA3000580004000
CANADA0000
UK0280000

Compare with summarize:

SQL
parse-csv
| extend "salary"=tonumber("salary")
| summarize "salary"=sum("salary") by "country", "occupation"

Output:

countryoccupationsalary
USADevops Engineer3000
USASoftware Engineer5800
CanadaStudent0
UKSoftware Engineer2800
UKSenior Software Engineer4000

Use pivot when you want values to become column headers. Use summarize when you want grouped rows.

Parser commands

These commands parse the raw response into a structured format:

CommandDescription
parse-jsonParse response as JSON
parse-csvParse response as CSV
parse-xmlParse response as XML
parse-yamlParse response as YAML

count

Return the total number of rows.

SQL
parse-json
| count

limit

Restrict the number of rows returned.

SQL
parse-json
| limit 10

scope

Set the document root to a nested property. Useful when your data is wrapped in a container object.

Input data:

JSON
{
  "meta": { "last-updated": "2021-08-09" },
  "count": 2,
  "users": [{ "name": "foo" }, { "name": "bar" }]
}

UQL query:

SQL
parse-json
| scope "users"

This returns only the users array, ignoring meta and count.

mv-expand

Expand multi-value arrays into separate rows. Use the syntax mv-expand "new_column"="array_column".

Input data:

JSON
[
  { "group": "A", "users": ["user a1", "user a2"] },
  { "group": "B", "users": ["user b1"] }
]

UQL query:

SQL
parse-json
| mv-expand "user"="users"

Output:

JSON
[
  { "group": "A", "user": "user a1" },
  { "group": "A", "user": "user a2" },
  { "group": "B", "user": "user b1" }
]

project kv()

Convert an object into key-value pair rows.

Input data:

JSON
{ "a": {"name":"a1"}, "b": {"name":"b1"}, "c": {"name":"c1"} }

UQL query:

SQL
parse-json
| project kv()

Output:

keyvalue
a{"name":"a1"}
b{"name":"b1"}
c{"name":"c1"}

To access a nested object, pass the property name as an argument:

SQL
parse-json
| project kv("data")

Note

The project kv() command is available from plugin version 0.8.7.

jsonata

Run a JSONata expression on the data. The JSONata query language provides powerful querying and transformation capabilities.

Basic example:

SQL
parse-json
| jsonata "items[price > 100]"

Complex example with chained commands:

SQL
parse-json
| scope "library"
| jsonata "loans@$L.books@$B[$L.isbn=$B.isbn].customers[$L.customer=id].{'customer': name, 'book': $B.title, 'due': $L.return}"
| count

The jsonata command can be combined with other UQL commands in a pipeline. Use it for filtering, transforming, or restructuring data.

Note

JSONata support in UQL is available from plugin version 0.8.8.

Comments

Lines starting with # are treated as comments and ignored during execution.

SQL
parse-json
# Filter to active users only
| where "status" == 'active'
# Sort by name
| order by "name" asc