CALL {}
The CALL {} (subquery) clause allows local execution of subqueries, which opens the door for many comfortable and efficient actions on a graph.
The subquery is executed once for each record in the input stream.
The subquery may be a returning or non-returning subquery. A returning subquery may change the amount of records, while a non-returning subquery will not.
The variables in the scope before the CALL {} clause are available after the clause, together with the variables returned by the subquery (in the case of a returning subquery).
Variables may be imported from the outer scope only in an opening WITH
clause, via simple projections (e.g. WITH n, m
), or via WITH *
(which imports all bound variables). The variables returned from a subquery may not override existing variables in the outer scope.
The CALL {} clause may be used for numerous purposes, such as: Post-UNION
processing, local environment for aggregations and actions on every input row, efficient operations using a limited namespace (via imports) and performing side-effects using non-returning subqueries. Let’s see some examples.
- Post-
UNION
processing.
We can easily get the cheapest and most expensive items in a store and set their of_interest
property to true
(to keep monitoring the ‘interesting’ items) using post-UNION
processing:
GRAPH.QUERY DEMO_GRAPH
CALL {
MATCH (s:Store {name: 'Walmart'})-[:SELLS]->(i:Item)
RETURN i AS item
ORDER BY price ASC
LIMIT 1
UNION
MATCH (s:Store {name: 'Walmart'})-[:SELLS]->(i:Item)
RETURN i AS item
ORDER BY price DESC
LIMIT 1
}
SET item.of_interest = true
RETURN item.name AS name, item.price AS price
We can utilize post-UNION
processing to perform aggregations over differently-matched entities. For example, we can count the number of customers and vendors that a store interacts with:
GRAPH.QUERY DEMO_GRAPH
CALL {
MATCH (s:Store {name: 'Walmart'})-[:SELLS_TO]->(c:Customer)
RETURN c AS interface
UNION
MATCH (s:Store {name: 'Walmart'})-[:BUYS_FROM]->(v:Vendor)
RETURN v AS interface
}
RETURN count(interface) AS interfaces
- Local environment for aggregations and actions on every input row.
Another key feature of the CALL {} clause is the ability to perform isolated aggregations on every input row. For example, let’s check if there is any correlation between the amount of sales per-product and the advertisement-intensity implemented for it in a particular month.
GRAPH.QUERY DEMO_GRAPH
MATCH (item:Item)
CALL {
WITH item
MATCH (item)-[s:SOLD_TO {advertisement_intensity: 10}]->(c:Customer)
WHERE s.date > '01-01-2023' AND s.date < '01-02-2023'
RETURN count(s) AS item_sales_ads_high
}
CALL {
WITH item
MATCH (item)-[s:SOLD_TO {advertisement_intensity: 5}]->(c:Customer)
WHERE s.date > '01-01-2023' AND s.date < '01-02-2023'
RETURN count(s) AS item_sales_ads_low
}
RETURN item.name AS name, item_sales_ads_high as high_ads_sales, item_sales_ads_low as low_ads_sales
- Side-effects.
We can comfortably perform side-effects using non-returning subqueries. For example, we can mark a sub-group of nodes in the graph withholding some shared property. Let’s mark all the items in a Walmart store that were sold more than 100 times as popular items, and return all items in the store:
GRAPH.QUERY DEMO_GRAPH
MATCH (item:Item)
CALL {
WITH item
MATCH (item)-[s:SOLD_TO]->(c:Customer)
WITH item, count(s) AS item_sales
WHERE item_sales > 100
SET item.popular = true
}
RETURN item