BQL Keywords
This article details the basic keywords in Brinqa query language (BQL) that make up the clauses of a query statement, including sorting and pagination.
Before you begin to write Brinqa queries, note the following:
-
Wildcards (*) are only supported for the
LIKE
andNOT LIKE
string functions. -
The names of the data models in the queries are case sensitive, but keywords are not case sensitive.
-
String must be wrapped in double quotes ("
string
"). -
Boolean, Number, and Date values do not have to be wrapped in double quotes.
Basic keywords
The following keywords make up the clauses of a query statement to perform various operations:
Keywords are not case sensitive in BQL, but they appear in uppercase letters in the examples to differentiate with other parts of the query.
FIND
The FIND
clause searches for an existing property or pattern in your data. It is followed by a data model. For example, the following query returns all vulnerabilities:
FIND Vulnerability
The above query is not specific and may not return useful results. To be more precise, you can add additional clauses to the query. See WHERE, THAT, and WITH.
AS
The AS
clause defines an aliased selector to be referenced in the WHERE
or RETURN
clause. An alias only exists for the duration of the specific query. For example, the following BQL statement creates an alias, f
, for Finding
and returns all findings with a critical risk rating:
FIND Finding AS f WHERE f.riskRating = "Critical"
You can create multiple aliases for different data models in a query as long as the two data models have a relationship. For example:
FIND Finding AS f THAT HAS Asset AS a WHERE f.severity = "Critical" AND a.status = "Confirmed active"
The above query creates an alias, f
, for Finding
and also an alias, a
, for Asset
and returns all critical findings on active assets.
For information about how to view data model relationships, see examine relationships between data models.
WHERE
The WHERE
clause adds constraints to the query and allows you to define specific criteria so you can find the exact data that you want to work with. WHERE
is followed by an attribute that must exist on the target model. For example, the following query returns all users whose first name starts with "W":
FIND Person AS p WHERE p.firstName STARTS WITH "W"
The firstName
attribute exists on the Person
data model, so the query runs successfully.
The following query returns all active findings with a medium severity level:
FIND Finding AS f WHERE f.status = "Confirmed active" AND f.severity = "Medium"
Both the status
and severity
attribute exist on the Finding
data model, so the query runs successfully. Check the data model reference for attributes and additional information.
THAT
The THAT
keyword must be followed by a relationship verb such as BELONGS
, CONTAINS
, HAS
, IS
, RELATES
, SUPPORTS
, etc. For more information on relationships and BQL, see query for relationships in BQL.
In BQL, prepositions such as IN
, ON
, AT
, TO
, or BY
can be used after relationship keywords for fluidity, but they are ignored in terms of query processing. Thus, RELATES TO
and RELATES
are functionally identical.
The relationship verbs are not case sensitive and you can use the relationship verb to reference any relationship between two data models. For example, the following query returns all hosts with vulnerabilities:
FIND Host AS h THAT HAS Vulnerability AS v
You can take the previous example and go a step further by returning all hosts with critical vulnerabilities:
FIND Host AS h THAT HAS Vulnerability AS v WHERE v.severity = "Critical"
Relationship verbs are bidirectional. For example, the following queries are both valid:
FIND Asset AS a THAT HAS Vulnerability AS v
FIND Vulnerability AS v THAT HAS Asset AS a
Furthermore, you can use RELATES TO
or RELATES
to express a relationship between data models without specifying or needing to know the exact name of the relationship.
For example, either of the following queries can be used to find Vulnerability
records that contain any type of relationship with VulnerabilityDefinition
:
FIND Vulnerability as v THAT RELATES TO VulnerabilityDefinition as v2
FIND Vulnerability as v THAT RELATES VulnerabilityDefinition as v2
On the other hand, the following query retrieves records where Vulnerability
has a defined IS
relationship with VulnerabilityDefinition
:
Find Vulnerability as v THAT IS VulnerabilityDefinition as v2
While RELATES TO
and RELATES
offer broader query results, covering any relationship type, specific keywords like IS
provide more targeted results based on a known relationship type.
RETURN
The RETURN
clause lets you define what you want to include in the query's result set. This can make your data more relevant by reducing unnecessary data and focusing on specific assets or properties.
You can only use RETURN
in reports, automations, and in explorer graphs. It is ignored in list views for assets, findings, or tickets. Additionally, you can only return the id
attribute in automations.
For example, when used in a report, the following query returns a number of unique vulnerabilities:
FIND Vulnerability AS v RETURN DISTINCT count(*)
This query is useful when you need to know the total count of unique vulnerabilities in your dataset. By using DISTINCT count(*)
, you ensure that each vulnerability is only counted once, giving you an accurate count.
When using the RETURN
clause in automations, make sure to return only the id
attribute to avoid your automation failing. If your query involves one-to-many relationships, you can get duplicated records unless you add RETURN DISTINCT <alias>.id
to the end of the query.
For example, the following query can be used in automation to get a list of unique user IDs and their associated remediation owner IDs:
FIND User AS u THAT OWNS RemediationOwner AS ro THAT OWNS_REMEDIATION Finding AS f WHERE f.severity = "High" RETURN DISTINCT u.id, ro.id
In the above query, User
and RemediationOwner
have a one-to-many relationship. By returning DISTINCT u.id
, you ensure that only unique user IDs are returned, preventing duplicates.
WITH
The WITH
clause allows parts of the query statement to be tethered together, connecting the results from one to be used as starting points or criteria in the next. For example, the following query returns hosts with vulnerabilities in ascending order:
FIND Vulnerability AS v THAT HAS Host AS h WITH v, h.displayName AS order ORDER BY order ASC
Multi-labeling
You can use the pipe symbol |
to query for different data models that share similar attributes. This is called Multi-labeling. For example, the following query returns all hosts and vulnerabilities that are sourced from the Qualys Vulnerability Management connector:
FIND Host|Vulnerability WHERE connectorNames = "Qualys Vulnerability Management"
The connectorNames
attribute exists on both Host and Vulnerability, allowing this query to work across both data models. In addition, the pipe symbol |
is used between the two data models to combine them in a single query.
The above query is less complex and time-consuming than running multiple queries to achieve the same result. For example, the following two queries retrieve the same number of hosts and vulnerabilities from Qualys, but the process is more time-consuming as you must run two separate queries:
FIND Host AS h WHERE h.connectorNames = "Qualys Vulnerability Management"
FIND Vulnerability AS v WHERE v.connectorNames = "Qualys Vulnerability Management"
Sorting and Pagination
You can sort and page through your data by utilizing the ORDER BY
, SKIP
, and LIMIT
subclauses in BQL. Sorting arranges records in either ascending or descending order to provide a more concise view, and pagination reduces the number of records returned from a query.
ORDER BY
You can use the ORDER BY
sub-clause to sort the queried data in either ascending or descending order. To sort the results in ascending order, use ASC
; and for descending order, use DESC
.
ORDER BY
is followed by an expression or field to indicate how to sort the data. For example, ORDER BY riskRating DESC
, sorts the records by their risk ratings in descending order.
SKIP
The SKIP
keyword is followed by a number to indicate how many records to skip in the output. For example, SKIP 20
, skips the first 20 records and returns the queried data from the 21st record.
LIMIT
The LIMIT
keyword is followed by a number to limit the number of records to return. For example, LIMIT 5
, returns five records from the queried data.
You can only use SKIP
and LIMIT
in reports, automations, and in explorer graphs. SKIP
and LIMIT
are ignored in all list views.
The following example uses ORDER BY
, SKIP
, and LIMIT
in a query together to demonstrate sorting and pagination:
FIND Asset AS a ORDER BY a.riskRating DESC SKIP 20 LIMIT 5
The above query retrieves assets from your data, sorts them in descending order by their risk ratings, skips the first 20 records, and then limits the result to 5 records, returning the 21st through 25th records from the sorted list.
If LIMIT
is not set in the query, it could result in a large number of records to return.
CASE statements
CASE
statements enable you to perform conditional evaluations within your queries. It evaluates conditions sequentially and returns a result based on the first condition met. If none of the conditions are met, the ELSE
clause provides a default result.
CASE
statements in BQL follow the same logic as CASE
expressions in Neo4j and SQL. For additional information, see SQL CASE documentation and Neo4j CASE documentation.
CASE
statements can only be used with the RETURN
keyword. It is limited to reports, automations, and explorer graphs, and is ignored in list views for assets, findings, or tickets.
The following BQL query uses a CASE
statement to categorize vulnerabilities based on their compliance status:
FIND Vulnerability AS v
RETURN
CASE
WHEN v.complianceStatus IN ["Met SLA", "Within SLA"] THEN "Compliant"
WHEN v.complianceStatus IN ["Out of SLA", "Exceeded SLA"] THEN "Not Compliant"
ELSE "No Value"
END AS "Compliance Status",
count(*) AS Count
Let's break down the components of the above BQL query to better understand how the CASE
statement is constructed and interpret the results:
-
FIND Vulnerability AS v RETURN
:- Retrieves records from the
Vulnerability
data model, assigns the aliasv
, andRETURN
specifies the data to be returned.
- Retrieves records from the
-
CASE
CASE
marks the start of a conditional block that evaluates conditions (WHEN
clauses) in sequence, returning the result of the first match.
-
WHEN v.complianceStatus IN ["Met SLA", "Within SLA"] THEN "Compliant"
WHEN
checks ifv.complianceStatus
is either "Met SLA" or "Within SLA" and returns "Compliant" if true.
-
WHEN v.complianceStatus IN ["Out of SLA", "Exceeded SLA"] THEN "Not Compliant"
WHEN
checks ifv.complianceStatus
is either "Out of SLA" or "Exceeded SLA" and returns "Not Compliant" if true.
-
ELSE "No Value"
ELSE
defines the default result and returns "No Value" if none of theWHEN
conditions are met.
-
END AS "Compliance Status"
END
marks the conclusion of theCASE
block and assigns the alias "Compliance Status" to the result.
-
count(*) AS Count
- Counts the number of matching records and assigns the alias "Count".
The following screenshot illustrates the results of the BQL query in a tabular report section using the advanced mode. Each row represents a compliance status category, showing the total count of vulnerabilities based on the CASE
statement WHEN
conditions, grouped as either "Compliant" or "Not Compliant."