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-
UNIONprocessing.
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