|
| 1 | +:description: Information about how to use Neo4j procedures using Cypher's `CALL` clause. |
| 2 | += Call procedures |
| 3 | + |
| 4 | +The `CALL` clause is used to call a procedure deployed in the database. |
| 5 | +Neo4j comes with a number of xref:procedures/built-in-procedures.adoc[built-in procedures]. |
| 6 | +Users can also develop custom procedures and deploy to the database (for more detals, see link:{neo4j-docs-base-uri}/java-reference/current/extending-neo4j/procedures/[Java Reference -> User-defined procedures]). |
| 7 | + |
| 8 | +[NOTE] |
| 9 | +==== |
| 10 | +The `CALL` clause is also used to evaluate a subquery. |
| 11 | +For more information about the `CALL` clause in this context, refer to the link:{neo4j-docs-base-uri}/cypher-manual/subqueries/call-subquery/[Cypher Manual -> `CALL` subquery]. |
| 12 | +==== |
| 13 | + |
| 14 | +The following graph is used for the examples below: |
| 15 | + |
| 16 | +[source, cypher, role=test-setup] |
| 17 | +---- |
| 18 | +CREATE (andy:Developer {name: 'Andy', born: 1991}), |
| 19 | + (beatrice:Developer {name: 'Beatrice', born: 1985}), |
| 20 | + (charlotte:Administrator {name: 'Charlotte', born: 1990}), |
| 21 | + (david:Administrator {name: 'David', born: 1994, nationality: 'Swedish'}), |
| 22 | + (andy)-[:KNOWS]->(beatrice), |
| 23 | + (beatrice)-[:KNOWS]->(charlotte), |
| 24 | + (andy)-[:KNOWS]->(david) |
| 25 | +---- |
| 26 | + |
| 27 | +[[standalone-procedure-calls]] |
| 28 | +== Standalone procedure calls |
| 29 | + |
| 30 | +A Cypher statement made up of only a single `CALL` clause is known as a standalone procedure call. |
| 31 | + |
| 32 | +.Call a procedure without arguments |
| 33 | +==== |
| 34 | +
|
| 35 | +This example calls the built-in procedure xref:procedures/built-in-procedures.adoc#procedure_db_labels[`db.labels()`], which lists all labels used in the database. |
| 36 | +
|
| 37 | +.Procedure call |
| 38 | +[source, cypher] |
| 39 | +---- |
| 40 | +CALL db.labels() |
| 41 | +---- |
| 42 | +
|
| 43 | +.Result |
| 44 | +[role="queryresult",options="header,footer",cols="1*<m"] |
| 45 | +|=== |
| 46 | +| label |
| 47 | +
|
| 48 | +| "Developer" |
| 49 | +| "Administrator" |
| 50 | +
|
| 51 | +1+d|Rows: 2 |
| 52 | +|=== |
| 53 | +
|
| 54 | +==== |
| 55 | + |
| 56 | +[NOTE] |
| 57 | +==== |
| 58 | +It is best practice to use parentheses when calling procedures, although Cypher allows for their omission when calling procedures of arity-0 (no arguments). |
| 59 | +Omission of parentheses is available only in a so-called standalone procedure call. |
| 60 | +==== |
| 61 | + |
| 62 | +.Call a procedure using literal arguments |
| 63 | +==== |
| 64 | +This example calls the procedure xref:procedures/built-in-procedures.adoc#procedure_dbms_checkConfigValue[`dbms.checkConfigValue()`], which checks the validity of a configuration setting value, using literal arguments. |
| 65 | +
|
| 66 | +.Query |
| 67 | +[source, cypher] |
| 68 | +---- |
| 69 | +CALL dbms.checkConfigValue('server.bolt.enabled', 'true') |
| 70 | +---- |
| 71 | +
|
| 72 | +.Result |
| 73 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 74 | +|=== |
| 75 | +| "valid" | "message" |
| 76 | +| true | "requires restart" |
| 77 | +
|
| 78 | +2+d|Rows: 1 |
| 79 | +|=== |
| 80 | +
|
| 81 | +==== |
| 82 | + |
| 83 | + |
| 84 | +.Call a procedure using parameters |
| 85 | +==== |
| 86 | +
|
| 87 | +This example calls the procedure `dbms.checkConfigValue()` using parameters as arguments. |
| 88 | +Each procedure argument is taken to be the value of a corresponding statement parameter with the same name (or `null` if no such parameter has been given). |
| 89 | +
|
| 90 | +.Parameters |
| 91 | +[source, parameters] |
| 92 | +---- |
| 93 | +{ |
| 94 | + "setting": "server.bolt.enabled", |
| 95 | + "value": "true" |
| 96 | +} |
| 97 | +---- |
| 98 | +
|
| 99 | +.Procedure call |
| 100 | +[source, cypher] |
| 101 | +---- |
| 102 | +CALL dbms.checkConfigValue($setting, $value) |
| 103 | +---- |
| 104 | +
|
| 105 | +.Result |
| 106 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 107 | +|=== |
| 108 | +| "valid" | "message" |
| 109 | +| true | "requires restart" |
| 110 | +
|
| 111 | +2+d|Rows: 1 |
| 112 | +|=== |
| 113 | +
|
| 114 | +==== |
| 115 | + |
| 116 | + |
| 117 | +.Call a procedure using both literal and parameter arguments |
| 118 | +==== |
| 119 | +
|
| 120 | +This example calls the procedure `dbms.checkConfigValue()` using both literal and parameter arguments. |
| 121 | +
|
| 122 | +.Parameters |
| 123 | +[source, parameters] |
| 124 | +---- |
| 125 | +{ |
| 126 | + "setting": "server.bolt.enabled" |
| 127 | +} |
| 128 | +---- |
| 129 | +
|
| 130 | +.Procedure call |
| 131 | +[source, cypher] |
| 132 | +---- |
| 133 | +CALL dbms.checkConfigValue($setting, 'true') |
| 134 | +---- |
| 135 | +
|
| 136 | +.Result |
| 137 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 138 | +|=== |
| 139 | +| "valid" | "message" |
| 140 | +| true | "requires restart" |
| 141 | +
|
| 142 | +2+d|Rows: 1 |
| 143 | +|=== |
| 144 | +
|
| 145 | +==== |
| 146 | + |
| 147 | +[[using-yield]] |
| 148 | +== Using `YIELD` to specify return columns and filter data |
| 149 | + |
| 150 | +The `YIELD` keyword is used to specify which procedure columns to return, allowing for the selection and filtering of the displayed information. |
| 151 | +`YIELD` is necessary if the procedure call is part of a larger Cypher statement (i.e. not a standalone procedure call). |
| 152 | + |
| 153 | +`YIELD *` is only valid in standalone procedure calls and only adds the ability to show deprecated return columns (there are no non-default return columns for called procedures). |
| 154 | + |
| 155 | +When `YIELD` is used outside of a standalone procedure call, variables must be explicitly named. |
| 156 | +This restriction simplifies query logic and protects against output variables from the procedure accidentally clashing with other query variables. |
| 157 | +For example, the following is not valid: |
| 158 | + |
| 159 | +.Not allowed |
| 160 | +[source, cypher, role=test-fail] |
| 161 | +---- |
| 162 | +CALL db.labels() YIELD * |
| 163 | +RETURN count(*) AS results |
| 164 | +---- |
| 165 | + |
| 166 | +.Yield specific return columns and filter on them |
| 167 | +==== |
| 168 | +
|
| 169 | +`YIELD` can be used to filter for specific results. |
| 170 | +This requires knowing the names of the arguments within a procedure's signature, which can either be found on the xref:procedures/built-in-procedures.adoc[built-in procedures page] or in the `signature` column returned by a xref:procedures/list-procedures.adoc[`SHOW PROCEDURES`] command. |
| 171 | +
|
| 172 | +.Find the argument names of `db.propertyKeys()` |
| 173 | +[source, cypher] |
| 174 | +---- |
| 175 | +SHOW PROCEDURES YIELD name, signature |
| 176 | +WHERE name = 'db.propertyKeys' |
| 177 | +RETURN signature |
| 178 | +---- |
| 179 | +
|
| 180 | +.Result |
| 181 | +[role="queryresult",options="header,footer",cols="1m"] |
| 182 | +|=== |
| 183 | +| signature |
| 184 | +
|
| 185 | +| "db.propertyKeys() :: (propertyKey :: STRING)" |
| 186 | +
|
| 187 | +1+d|Rows: 1 |
| 188 | +|=== |
| 189 | +
|
| 190 | +It is then possible to use these argument names for further query filtering. |
| 191 | +Note that if the procedure call is part of a larger query, its output must be named explicitly. |
| 192 | +In the below example, `propertyKey` is aliased as `prop` and then used later in the query to link:{neo4j-docs-base-uri}/cypher-manual/functions/aggregating/#functions-count/[count] the occurrence of each property in the graph. |
| 193 | +
|
| 194 | +.Filter on specific argument |
| 195 | +[source, cypher] |
| 196 | +---- |
| 197 | +CALL db.propertyKeys() YIELD propertyKey AS prop |
| 198 | +MATCH (n) |
| 199 | +WHERE n[prop] IS NOT NULL |
| 200 | +RETURN prop, count(n) AS numNodes |
| 201 | +---- |
| 202 | +
|
| 203 | +.Result |
| 204 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 205 | +|=== |
| 206 | +| prop | numNodes |
| 207 | +
|
| 208 | +| "name" | 4 |
| 209 | +| "born" | 4 |
| 210 | +| "nationality" | 1 |
| 211 | +
|
| 212 | +2+d|Rows: 3 |
| 213 | +|=== |
| 214 | +
|
| 215 | +==== |
| 216 | + |
| 217 | +[[void-procedures]] |
| 218 | +=== Note on VOID procedures |
| 219 | + |
| 220 | +Neo4j supports the notion of `VOID` procedures. |
| 221 | +A `VOID` procedure is a procedure that does not declare any result fields and returns no result records. |
| 222 | +`VOID` procedure only produces side-effects and does not allow for the use of `YIELD`. |
| 223 | + |
| 224 | +Calling a `VOID` procedure in the middle of a larger query will simply pass on each input record (i.e., it acts like link:{neo4j-docs-base-uri}/cypher-manual/clauses/with/[`WITH *`] in terms of the record stream). |
| 225 | + |
| 226 | +[[optional-call]] |
| 227 | +== Optional procedure calls |
| 228 | + |
| 229 | +`OPTIONAL CALL` allows for an optional procedure call. |
| 230 | +Similar to link:{neo4j-docs-base-uri}/cypher-manual/current/clauses/optional-match/[`OPTIONAL MATCH`], any empty rows produced by `OPTIONAL CALL` will return `null`. |
| 231 | + |
| 232 | +.Difference between `CALL` and `OPTIONAL CALL` |
| 233 | +==== |
| 234 | +
|
| 235 | +This query uses the link:{neo4j-docs-base-uri}/apoc/current/overview/apoc.neighbors/apoc.neighbors.tohop[`apoc.neighbors.tohop()`] procedure (part of Neo4j's link:{neo4j-docs-base-uri}/apoc/current/[APOC Core library]), which returns all nodes connected by the given relationship type within the specified distance (1 hop, in this case) and direction. |
| 236 | +
|
| 237 | +.Regular procedure call |
| 238 | +[source, cypher] |
| 239 | +---- |
| 240 | +MATCH (n) |
| 241 | +CALL apoc.neighbors.tohop(n, "KNOWS>", 1) |
| 242 | +YIELD node |
| 243 | +RETURN n.name AS name, collect(node.name) AS connections |
| 244 | +---- |
| 245 | +
|
| 246 | +Note that the result does not include the nodes in the graph without any outgoing `KNOWS` relationships connected to them. |
| 247 | +
|
| 248 | +.Result |
| 249 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 250 | +|=== |
| 251 | +| name | connections |
| 252 | +
|
| 253 | +| "Andy" |
| 254 | +| ["Beatrice", "David"] |
| 255 | +
|
| 256 | +| "Beatrice" |
| 257 | +| ["Charlotte"] |
| 258 | +
|
| 259 | +2+d|Rows: 2 |
| 260 | +|=== |
| 261 | +
|
| 262 | +The same query is used below, but `CALL` is replaced with `OPTIONAL CALL`. |
| 263 | +
|
| 264 | +.Optional procedure call |
| 265 | +[source, cypher] |
| 266 | +---- |
| 267 | +MATCH (n) |
| 268 | +OPTIONAL CALL apoc.neighbors.tohop(n, "KNOWS>", 1) |
| 269 | +YIELD node |
| 270 | +RETURN n.name AS name, collect(node.name) AS connections |
| 271 | +---- |
| 272 | +
|
| 273 | +The result now includes the two nodes without any outgoing `KNOWS` relationships connected to them. |
| 274 | +
|
| 275 | +.Result |
| 276 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 277 | +|=== |
| 278 | +| name | connections |
| 279 | +
|
| 280 | +| "Andy" |
| 281 | +| ["Beatrice", "David"] |
| 282 | +
|
| 283 | +| "Beatrice" |
| 284 | +| ["Charlotte"] |
| 285 | +
|
| 286 | +| "Charlotte" |
| 287 | +| [] |
| 288 | +
|
| 289 | +| "David" |
| 290 | +| [] |
| 291 | +
|
| 292 | +2+d|Rows: 4 |
| 293 | +|=== |
| 294 | +
|
| 295 | +==== |
| 296 | + |
0 commit comments