Skip to navigation

The query task extracts data from an object or array variable and passes the result to a later task.

Use cases

Use the query task to do the following:

  • Extract a value from a variable for evaluation or other downstream logic.
  • Filter and manipulate data with the query syntax, such as returning only the array elements that match a condition.

To retrieve a value without adding a task to the canvas, apply a task input query to the input field instead. Use the query task when the result needs to be an output variable in its own right, such as when more than one later task reads the same reshaped data.

To query the output of a Gateway service, use the result.stdout_json property of the runService task output. This property contains the service’s standard output parsed as JSON.

To confirm the finish state of child job loops, use the loop[*].status query syntax to extract the resulting status of each child job run in the childJob task output.

Properties

IncomingTypeRequiredDescription
pass_on_nullBooleanYesDetermines the return_data value and the transition (success or failure) that the task takes if the query fails. For more information, see Using the pass on null variable.
queryStringYesThe query expression. For the supported syntax, see Query syntax.
objObjectYesThe object (or array) to query. The value can come from a job variable, a static value, or an outgoing variable from an earlier task.
OutgoingDescription
return_dataThe query results.

Using the pass on null variable

The pass_on_null property determines the return_data value and the transition that the task takes when the query doesn’t match the object:

Scenariopass_on_nullreturn_dataTransition
The query references a property that doesn’t exist.trueThe entire obj value, unchanged. The task passes the original object through.Success
The query references a property that doesn’t exist.falseThe task returns no value. The result is undefined.Failure
The query references a property at least two levels deep, and none of those levels exist.true or falsenullSuccess

In the last scenario, pass_on_null has no effect. The task returns null and takes the success transition even when pass_on_null is false. Check for a null result before a later task uses it.

Task input queries handle failures differently so that missing or invalid data is caught as early as possible in the workflow. A task input query doesn’t use pass_on_null. If a task input query can’t find a key or index, the task takes its error transition, and the error message identifies the query. If a task input query finds a key whose value is null, the query succeeds and passes null to the input. For more information, see Task input query.

Query syntax

The examples in this section query the following object, which contains device data from a site:

{
"status": "active",
"site": { "name": "ATL-DC1", "region": "us-east" },
"devices": [
{ "hostname": "atl-core-01", "role": "router", "cpu_percent": 85 },
{ "hostname": "atl-core-02", "role": "router", "cpu_percent": 42 },
{ "hostname": "atl-access-01", "role": "switch", "cpu_percent": 30 }
],
"devices_by_site": {
"atl": [
{ "hostname": "atl-core-01", "role": "router" },
{ "hostname": "atl-access-01", "role": "switch" }
],
"dfw": [
{ "hostname": "dfw-core-01", "role": "router" },
{ "hostname": "dfw-access-01", "role": "switch" }
]
},
"selected": { "site": "atl" },
"config": { "ietf-system:system": { "contact": "neteng" } }
}

The following table lists the supported query syntax. A query can start with or without a period. For example, site.name and .site.name return the same value.

FeatureDescriptionQueryResult
Top-level keyReturns the value of a key at the top level of the object.status"active"
Property accessAccesses a nested property by using dot notation.site.name"ATL-DC1"
Array indexAccesses an array element by index.devices[0]{ "hostname": "atl-core-01", "role": "router", "cpu_percent": 85 }
Array pluckReturns the value of one property from every item in an array.devices.hostname["atl-core-01", "atl-core-02", "atl-access-01"]
WildcardReturns every value in an object or every element in an array.site[*]["ATL-DC1", "us-east"]
Array filter, first matchReturns the first array element that matches a condition.devices[role=router].hostname"atl-core-01"
Array filter, all matchesReturns all array elements that match a condition. Prefix the condition with *. Returns an array even if one or no elements match.devices[*role=router].hostname["atl-core-01", "atl-core-02"]
Comparison operatorsCompares values in a filter condition. The operators are >, <, >=, and <=.devices[*cpu_percent>80].hostname["atl-core-01"]
Boolean ANDCombines multiple conditions in a filter. Use &.devices[*role=router & cpu_percent<50].hostname["atl-core-02"]
Not-equal filterReturns the array elements in which a property doesn’t match the value. Use !=, or use !~ for a regular expression.devices[*role!=router].hostname["atl-access-01"]
Regular expression filterMatches values against a regular expression. Use ~.devices[*hostname~/^atl-core/].cpu_percent[85, 42]
OR fallback pathTries the first path. If the first path is falsy or missing, uses the second path.site.alias|site.name"ATL-DC1"
Deep querySearches all levels of a nested structure. Use [**] before the filter.devices_by_site[**][*role=switch].hostname["atl-access-01", "dfw-access-01"]
Inner queryEvaluates a nested query and uses the result as a key or filter value.devices_by_site[{selected.site}].hostname["atl-core-01", "atl-access-01"]

For how these queries differ from Platform 6.4.0 task input queries, see Query syntax across Platform versions.

Helper functions

A helper function transforms or filters a value from a job or task variable or that the preceding part of the query returns.

To call a helper function on a value that an earlier part of the query returns, add a period before the function. For example, config.:getLiteral(ietf-system:system) calls :getLiteral() on the value of config. Use dot notation for every part of the path except a key that contains a special character. Use :getLiteral() only for that key.

A helper function can also start a query. It then reads from the top level of the object. For example, in the object { "ietf-system:system": { "contact": "neteng" } }, the query :getLiteral(ietf-system:system).contact returns "neteng".

Helper functionDescriptionWhen to use it
:getLiteral(key)Returns the value of a property and reads the key as plain text. 6.7.0+Use it for any key that contains a special character (., :, |, ?, (, ), [, ], {, or }). It reads the entire argument as the key, which makes it the recommended way to access these keys.
:get(key)Returns the value of a property. Unlike dot notation, it accesses keys that contain special characters, such as ., :, and |. It does not access keys that contain ?, ,, (, ), [, ], {, or }. 6.4.0+Supported for backward compatibility. Use it with caution. :getLiteral(key) accesses every key that :get(key) does, so use :getLiteral(key) instead.
:unique()Removes duplicate values from an array.Use it after a query that plucks a property from an array and returns repeated values, such as a list of roles or site names. It works on arrays only, not objects.
:exists(key)Returns only the entries that have the property.Use it to filter an array or a keyed object down to the entries that define a property, before a later task reads that property.

Query a key that contains special characters

The query syntax assigns a meaning to some characters. Because the query library reads these characters as part of the query, dot notation can’t access a property whose key contains one. For example, the query region?id treats ? as query syntax and returns undefined. A hyphen (-) and an underscore (_) have no meaning in the query syntax, so use dot notation for a key that contains either one.

The following table lists the characters and what the query syntax uses them for:

CharacterUse in query syntax
.Separates the parts of a path, such as site.name.
:Starts a helper function, such as :unique().
|Separates alternative paths, such as site.alias|site.name.
?Marks a query parameter.
( and )Enclose the argument of a helper function.
[ and ]Enclose an array index or a filter condition.
{ and }Enclose an inner query.

Use dot notation wherever possible. To access a key that contains a special character, use :getLiteral(). It accesses a key that contains any of the characters in the previous table. It reads its argument as plain text, so a ? or . in the key is always part of the key, and you don’t enclose the key in quotation marks. Only ) and \ need an escape character. For more information, see Escape characters in the key.

:getLiteral() works at the start of a query and after a path. In the following examples, region?id is at the top level of the object, and mgmt:vlan is in the site object.

The examples in this section query the following object:

{
"region?id": "us-east",
"site": { "mgmt:vlan": 100 },
"config": { "ietf-system:system": { "contact": "neteng" } }
}
Key to accessQueryResult
region?id:getLiteral(region?id)"us-east"
mgmt:vlansite.:getLiteral(mgmt:vlan)100
ietf-system:systemconfig.:get(ietf-system:system).contact"neteng"

The :get() helper function is supported for backward compatibility, but use it with caution. It accesses a key that contains any special character except ?, ,, (, ), [, ], {, and }. For example, it accesses keys that contain ., :, or |. :getLiteral() accesses every key that :get() does, so use :getLiteral() instead.

Don’t use bracket notation, such as ["device_name"], to access a key. In the query task and in task input queries, use dot notation to access device_name. To access a key that contains a special character, use :getLiteral().

Escape characters in the key

:getLiteral() reads the key up to the first ) that you don’t escape. To include a ) or a backslash (\) in the key, escape the character with a backslash:

To includeEnter
)\)
\\\

You don’t need to escape any other character, but every backslash must be part of \\ or \).

The examples in this section query the following object. The key Gi0/1 (uplink) contains a ). The key CORP\netadmin contains a backslash. JSON requires every backslash in a string to be escaped, so the object writes this key as "CORP\\netadmin".

{
"Gi0/1 (uplink)": { "status": "up" },
"CORP\\netadmin": { "privilege": 15 }
}
Key in the example objectQueryResult
Gi0/1 (uplink):getLiteral(Gi0/1 (uplink\)).status"up"
CORP\netadmin:getLiteral(CORP\\netadmin).privilege15

The query package shares the same escape rule as JSON for backslashes, so enter each backslash in the key as \\ to match the JSON. For example, the key CORP\netadmin becomes :getLiteral(CORP\\netadmin). This matches the JSON spelling, so no edits are needed to the key. If a JSON viewer shows the key as CORP\\netadmin, don’t double the backslashes again: CORP\\\netadmin looks for a key with two backslashes.

Invalid :getLiteral() calls

A :getLiteral() call is invalid in any of the following cases. These calls are invalid regardless of what the object contains.

ProblemExample
The call isn’t closed.:getLiteral(a
An escaped ) hides the closing ), so the call isn’t closed.:getLiteral(a\)
The key contains a backslash that isn’t part of \\ or \).:getLiteral(a\b)
Another (...) group immediately follows the call.:getLiteral(a)(b)

An invalid call returns undefined, so the query finds no value. Platform also skips everything after the invalid call, up to the next | or the end of the query. For example, in :getLiteral(a\b).c, Platform skips .c. In :getLiteral(a\b).c|d, Platform skips .c and returns the value of the d key.

Because the query finds no value, the result depends on pass_on_null. For more information, see Using the pass on null variable.

Remove duplicate values

:unique() returns each value in an array only once.

The following example uses an object in which each device is an element of the devices array. The query plucks the role value from every element and removes the duplicates.

{
"devices": [
{ "hostname": "atl-core-01", "role": "router" },
{ "hostname": "atl-core-02", "role": "router" },
{ "hostname": "atl-access-01", "role": "switch" }
]
}
devices.role.:unique()

Result:

["router", "switch"]

:unique() works on arrays only, not objects.

Return entries that have a property

:exists() returns only the entries of an array or object that have the specified property.

The following example uses an object in which each device is an entry in a keyed object. The query returns the devices that have an owner property.

{
"devices_by_name": {
"atl-core-01": { "role": "router", "owner": "neteng" },
"atl-access-01": { "role": "switch", "owner": "neteng" },
"atl-core-02": { "role": "router" }
}
}
devices_by_name.:exists(owner)

Result:

{
"atl-core-01": { "role": "router", "owner": "neteng" },
"atl-access-01": { "role": "switch", "owner": "neteng" }
}

:exists() evaluates the entries of the value that precedes it. If that part of the query doesn’t return a value, :exists() returns {}.

Query syntax across Platform versions

In Platform 6.7.0 and later, the query task and task input queries use the same query syntax. The following list describes what’s shared and what isn’t:

  • Shared syntax: Task input queries support the full syntax on this page, including filters, helper functions, and :getLiteral(). Before Platform 6.7.0, task input queries supported data retrieval from objects and arrays only.
  • Separate failure handling: The query task uses pass_on_null when a query doesn’t match. A task input query takes the task’s error transition instead. For more information, see Using the pass on null variable.
  • Query task syntax: The query task syntax didn’t change in Platform 6.7.0 except for the addition of :getLiteral(). Query tasks return the same values as before.