$path

There are several “helpers” in OpenAF to help to “query” array of maps that help to make code cleaner. For a complete list (like $from) see on the end of this document.

$path is based on JMESPath library that makes it pratical to perform queries with just a string query but can be difficult to “read”. To help understanding JMESPath where is a quick guide.

Input

$path can be used to query both javascript maps and arrays. Let’s use an example of a map with an array that you can easily replicate:

var obj = io.listFiles(getOpenAFPath())

Now you can access the files array of the resulting map obj as well as any of the maps inside the files array:

isMap( obj )
// true
isArray( $path(obj, "files") )
// true
isMap( $path(obj, "files[0]") )
// true
$path(obj, "files[0].filename")
// openaf-sb

Queries

There are 6 main categories of queries:

Category Description
Slicing When querying arrays it’s possible to “slice” them in different ways (examples: the first five; from the third to the fifth; the first two; the last element; etc.).
MultiSelect As with projections it’s also possible to “project” multiple fields.
Filters It’s possible to apply simple conditions (including using functions) to query an array.
Projections Given the inputs it’s possible to “project” any fields necessary even if in keys.
Pipe Using the same unix “pipe” mechanism it’s possible to apply different categories of queries in sequence.
Functions It’s possible to apply a set of built-in functions over the queried fields and use the result also to build “filters”

Slicing

Slicing arrays makes it easy to filter for specific records on an array:

$path([1,2,3,4,5,6,7,8,9,10], "[0:5]")
// [1, 2, 3, 4, 5]
$path([1,2,3,4,5,6,7,8,9,10], "[::2]")
// [1, 3, 5, 7, 9]
$path([1,2,3,4,5,6,7,8,9,10], "[::3]")
// [1, 4, 7, 10]
$path([1,2,3,4,5,6,7,8,9,10], "[::-1]")
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
$path([1,2,3,4,5,6,7,8,9,10], "[::-2]")
// [10, 8, 6, 4, 2]
$path([1,2,3,4,5,6,7,8,9,10], "[-1]")
// 10
$path([1,2,3,4,5,6,7,8,9,10], "[-5::]")
// [6, 7, 8, 9, 10]
$path([1,2,3,4,5,6,7,8,9,10], "[-5::2]")
// [6, 8, 10]

$path(obj, "files[0:5]")   // or $path(obj.files, "[0:5]")
// An array with the first 5 elements
$path(obj, "files[:5]")
// Again, the same array with the first 5 elements

Multi-select

Given an input if nothing is specified all fields will be output. If you provide a specific field, only that one will be output. But it’s possible to specify multi-fields:

$path(obj, "files[].[filename, size]")
// an array where each element is another array where the first value is _filename_ and the second is _size_
$path(obj, "files[].{f: filename, s: size}")
// an array where each element is a map where _f_ is the value of 'filename' and _s_ is the value of 'size'

Filter

Given an input it’s possible to use the existing fields to filter the result:

$path(obj, "files[?size>`1000000`]")
// an array with the files whose size is bigger than 1MB
$path(obj, "files[?filename=='openaf.jar']")
// an array with one entry where filename is "openaf.jar"
$path(obj, "files[?filename=='openaf.jar'].size")
// an array with one entry with the size value of the filename is "openaf.jar"

Projections

Projecting specific fields from an array of maps:

$path(obj, "files[].filename")
// An array of each value of "filename" on the "files" array
$path([ { x: 1, y: -1 },  {x: 2, y: 2 } ], "[].x")
// [1, 2]
$path({ x: 1, y: -1, z: 0 }, "*")
// [1, -1, 0]
$path([ { point: { x: 1,y: -1 }, level: { x: -99, y: 99 } }, { point: {x: 2, y: 2 } } ], "[].*.x")
// [[ 1, -99], [ 2 ]]

Pipe

Very quickly you might need to apply a sequence of filters, slicing, multi-selects and projections:

$path(obj, "files[?size>`1000000`] | [?filename=='openaf.jar']")
// An array with the element whose 'filename' is "openaf.jar" and whose 'size' is bigger than 1MB
$path(obj, "files[?size>`1000000`] | [?filename=='openaf.jar'] | [0]")
// The first element of an array with the element whose 'filename' is "openaf.jar" and whose 'size' is bigger than 1MB
$path(obj, "files[?size>`1000000`] | [?filename=='openaf.jar'] | [0].filename")
// The 'filename' of the first element of an array with the element whose 'filename' is "openaf.jar" and whose 'size' is bigger than 1MB
$path(obj, "files[?size>`1000000`] | [?filename=='openaf.jar'] | [0] | @.filename")
// Same as the previous result

Functions

It’s possible to apply functions to fields and arrays on the expression used in $path:

Function Description Example
abs(number) The absolute value of a numeric field $path([{x:1,y:-1},{x:2,y:2}], "[].{y:abs(y)}")
avg(arrayNumber) The average value of an array of numeric fields $path([ {x:1,y:-1}, {x:2,y:2} ], "avg([].y)")
contains(string/array, any) Returns true of false if a string field contains a specific value $path(obj, "files[?contains(filename, 'openaf.jar') == `true`")
ceil(numer) Returns the smallest integer that is equal or less than a specific numeric field value $path([{x: 1.2, y: -1.8},{x: 2.2, y: 2.0}], "[].ceil(y)")
ends_with(string, array) Returns true if a field has the provided suffix $path(obj, "files[?ends_with(filename, '.jar')]")
floor(number) Returns the greatest integer that is equal or greater than a specific numeric field value $path([ {x:1.2,y:-1.8}, {x:2.2,y:2.0} ], "[].floor(y)")
join(string, arrayString) Returns a delimited list with the values of a specific array field $path(obj, "join(', ', files[].filename)")
keys(object) Returns a list of fields for a corresponding map $path(obj, "keys(files[0])")
length(string/array/object) Returns the size of any array or list $path(obj, "length(keys(files[0]))")
map(expression, array) Returns an array mapping $path(obj, "map(&filename == 'openaf.jar', files[])"
max(number) Returns the maximum of a numeric field $path(obj, "max(files[].size)")
max_by(array, expression) Returns the element for which the expression is the maximum $path(obj, "max_by(files[], &size)")
merge(object, object) Returns the merge of two objects $path([{x:1},{y:0}], "merge([0],[1]))
min(number) Returns the minimum of a numeric field $path(obj, "min(files[].size)")
min_by(array, expression) Returns the element for which the expression is the minimum $path(obj, "min_by(files[], &size)")
not_null(any) Returns the non-null value between the provided fields $path([{a:null,b:1}, {a:2,b:null}], "[].not_null(a,b)")
reverse(array) Reverse the provided array $path([1,2,3], "reverse(@)")
sort(array) Sorts the provided array $path([3,1,2], "sort(@)")
sort_by(array, expression) Sorts the provided array by the provided expression $path(obj, "sort_by(files[], &size)")
starts_with(string, array) Returns true if a field has the provided prefix $path(obj, "files[?starts_with(filename, 'openaf.jar')]")
sum(array) Sums the numberic field of a provided array $path(obj, "sum(files[].size)")
to_array(any) Transforms any input into an array $path(obj, "to_array(`true`)")
to_string(any) Transforms any input into a string $path(obj, "to_string(`123`)")
to_number(any) Transforms any input into a number $path(obj, "to_number(`123`)")
type(any) Returns the type of any input $path(obj, "type(to_number(`123`))")
values(a) Returns an array with all the values of a map $path(obj, "values(files[0])")

Other libraries in OpenAF