|
| 1 | +[[match-entities]] |
| 2 | += Match entities |
| 3 | +:description: This section describes procedures and functions for matching entities. |
| 4 | + |
| 5 | +The library provides 2 procedure for matching entities: |
| 6 | + |
| 7 | +- apoc.node.match |
| 8 | +- apoc.rel.match |
| 9 | + |
| 10 | +[[matching-node]] |
| 11 | +== Matching nodes |
| 12 | + |
| 13 | +[.emphasis] |
| 14 | +"apoc.node.match(['Label'], identProps:{key:value, ...}, onMatchProps:{key:value,...})" - match nodes with dynamic labels, with support for setting properties on matched nodes |
| 15 | + |
| 16 | +=== Signature |
| 17 | + |
| 18 | +[source] |
| 19 | +---- |
| 20 | +apoc.node.match(label :: LIST? OF STRING?, identProps :: MAP?, onMatchProps = {} :: MAP?) :: (node :: NODE?) |
| 21 | +---- |
| 22 | + |
| 23 | +=== Input parameters |
| 24 | +[.procedures, opts=header] |
| 25 | +|=== |
| 26 | +| Name | Type | Default | Description |
| 27 | +| labels | LIST? OF STRING? | null | The list of labels used for the generated MATCH statement. Passing `null` or an empty list will match a node without any constraints on labels. `null` or empty strings within the list are not supported. |
| 28 | +| identProps | MAP? | null | Properties that are used for MATCH statement. |
| 29 | +| onMatchProps | MAP? | {} | Properties that are set when a node is matched. |
| 30 | +|=== |
| 31 | + |
| 32 | +=== Output parameters |
| 33 | +[.procedures, opts=header] |
| 34 | +|=== |
| 35 | +| Name | Type |
| 36 | +|node|NODE? |
| 37 | +|=== |
| 38 | + |
| 39 | +This procedure provides a more flexible and performant way of matching nodes than Cypher's https://neo4j.com/docs/cypher-manual/current/clauses/match/[`MATCH`^] clause. |
| 40 | + |
| 41 | +=== Usage Examples |
| 42 | +The example below shows equivalent ways of matching a node with the `Person` label, with a `name` property of "Billy Reviewer": |
| 43 | + |
| 44 | +// tag::tabs[] |
| 45 | +[.tabs] |
| 46 | + |
| 47 | +.apoc.node.match |
| 48 | +[source,cypher] |
| 49 | +---- |
| 50 | +CALL apoc.node.match( |
| 51 | + ["Person"], |
| 52 | + {name: "Billy Reviewer"}, |
| 53 | + {lastSeen: datetime()} |
| 54 | +) |
| 55 | +YIELD node |
| 56 | +RETURN node; |
| 57 | +---- |
| 58 | + |
| 59 | +.MATCH clause |
| 60 | +[source,cypher] |
| 61 | +---- |
| 62 | +MATCH (node:Person {name: "Billy Reviewer"}) |
| 63 | +SET node.lastSeen = datetime() |
| 64 | +RETURN node; |
| 65 | +---- |
| 66 | +// end::tabs[] |
| 67 | + |
| 68 | +.Results |
| 69 | +[opts="header"] |
| 70 | +|=== |
| 71 | +| node |
| 72 | +| (:Person {name: "Billy Reviewer", lastSeen: 2020-11-24T11:33:39.319Z}) |
| 73 | +|=== |
| 74 | + |
| 75 | +But this procedure is mostly useful for matching nodes that have dynamic labels or properties. |
| 76 | +For example, we might want to create a node with labels or properties passed in as parameters. |
| 77 | + |
| 78 | +The following creates `labels` and `properties` parameters: |
| 79 | + |
| 80 | +[source,cypher] |
| 81 | +---- |
| 82 | +:param labels => (["Person"]); |
| 83 | +:param identityProperties => ({name: "Billy Reviewer"}); |
| 84 | +:param onMatchProperties => ({placeOfBirth: "Stars of the milky way, Always at the time of sunrise."}); |
| 85 | +---- |
| 86 | + |
| 87 | +The following match a node with labels and properties based on `labels` and `identityProperties`, furthermore sets a new property based on `onMatchProperties`: |
| 88 | + |
| 89 | +[source,cypher] |
| 90 | +---- |
| 91 | +CALL apoc.node.match($labels, $identityProperties, $onMatchProperties) |
| 92 | +YIELD node |
| 93 | +RETURN node; |
| 94 | +---- |
| 95 | + |
| 96 | +.Results |
| 97 | +[opts="header"] |
| 98 | +|=== |
| 99 | +| node |
| 100 | +| (:Person {name: "Billy Reviewer", lastSeen: 2020-11-24T11:33:39.319Z, placeOfBirth: "Stars of the milky way, Always at the time of sunrise."}) |
| 101 | +|=== |
| 102 | + |
| 103 | + |
| 104 | +In addition, we can use the `apoc.node.match` along with the `apoc.load.json` to dynamically set nodes starting from a JSON. |
| 105 | + |
| 106 | +For example, given the following dataset: |
| 107 | + |
| 108 | +[source,cypher] |
| 109 | +---- |
| 110 | +CREATE (giacomo:Person:Actor {name: 'Giacomino Poretti'}), |
| 111 | + (aldo:Person:Actor {name: 'Cataldo Baglio'}), |
| 112 | + (giovanni:Person:Actor {name: 'Giovanni Storti'}) |
| 113 | +---- |
| 114 | + |
| 115 | +and the following `all.json` file: |
| 116 | + |
| 117 | +[source,json] |
| 118 | +---- |
| 119 | +[ |
| 120 | + { |
| 121 | + "labels":[ |
| 122 | + "Person", |
| 123 | + "Actor" |
| 124 | + ], |
| 125 | + "matchProps":{ |
| 126 | + "name":"Giacomino Poretti" |
| 127 | + }, |
| 128 | + "setProps":{ |
| 129 | + "bio":"Giacomo Poretti was born on April 26 1956 in Busto Garolfo", |
| 130 | + "Alias":"Tafazzi" |
| 131 | + } |
| 132 | + }, |
| 133 | + { |
| 134 | + "labels":[ |
| 135 | + "Person", |
| 136 | + "Actor" |
| 137 | + ], |
| 138 | + "matchProps":{ |
| 139 | + "name":"Giovanni Storti" |
| 140 | + }, |
| 141 | + "setProps":{ |
| 142 | + "bio":"Giovanni Storti was born ...", |
| 143 | + "Alias":"Rezzonico" |
| 144 | + } |
| 145 | + }, |
| 146 | + { |
| 147 | + "labels":[ |
| 148 | + "Person", |
| 149 | + "Actor" |
| 150 | + ], |
| 151 | + "matchProps":{ |
| 152 | + "name":"Cataldo Baglio" |
| 153 | + }, |
| 154 | + "setProps":{ |
| 155 | + "bio":"Cataldo Baglio was born somewhere", |
| 156 | + "Alias":"Ajeje" |
| 157 | + } |
| 158 | + } |
| 159 | +] |
| 160 | +
|
| 161 | +---- |
| 162 | + |
| 163 | + |
| 164 | +we can execute the following query to MATCH and SET the `Person:Actor` nodes: |
| 165 | + |
| 166 | +[source,cypher] |
| 167 | +---- |
| 168 | +CALL apoc.load.json("all.json") YIELD value |
| 169 | +WITH value |
| 170 | +CALL apoc.node.match(value.labels, value.matchProps, value.setProps) |
| 171 | +YIELD node |
| 172 | +RETURN node |
| 173 | +---- |
| 174 | + |
| 175 | +.Results |
| 176 | +[opts="header"] |
| 177 | +|=== |
| 178 | +| node |
| 179 | +| (:Actor:Person {name: "Giacomino Poretti",bio: "Giacomo Poretti was born on April 26 1956 in Busto Garolfo",Alias: "Tafazzi"}) |
| 180 | +| (:Actor:Person {name: "Giovanni Storti",bio: "Giovanni Storti was born ...",Alias: "Rezzonico"}) |
| 181 | +| (:Actor:Person {name: "Cataldo Baglio",bio: "Cataldo Baglio was born somewhere",Alias: "Ajeje"}) |
| 182 | +|=== |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | +[[matching-relationship]] |
| 187 | +== Matching relationships |
| 188 | + |
| 189 | +[.emphasis] |
| 190 | +"apoc.rel.match(startNode, relType, identProps:{key:value, ...}, endNode, onMatchProps:{key:value, ...})" - match relationship with dynamic type, with support for setting properties on match |
| 191 | + |
| 192 | +=== Signature |
| 193 | + |
| 194 | +[source] |
| 195 | +---- |
| 196 | +apoc.rel.match(startNode :: NODE?, relationshipType :: STRING?, identProps :: MAP?, endNode :: NODE?, onMatchProps = {} :: MAP?) :: (rel :: RELATIONSHIP?) |
| 197 | +---- |
| 198 | + |
| 199 | +=== Input parameters |
| 200 | +[.procedures, opts=header] |
| 201 | +|=== |
| 202 | +| Name | Type | Default | Description |
| 203 | +| startNode | NODE? | null | Start node of the MATCH pattern. |
| 204 | +| relationshipType | STRING? | null | Relationship type of the MATCH pattern. |
| 205 | +| identProps | MAP? | null | Properties on the relationships that are used for MATCH statement. |
| 206 | +| endNode | NODE? | null | End node of the MATCH pattern. |
| 207 | +| onMatchProps | MAP? | {} | Properties that are set when the relationship is matched. |
| 208 | +|=== |
| 209 | + |
| 210 | +=== Output parameters |
| 211 | +[.procedures, opts=header] |
| 212 | +|=== |
| 213 | +| Name | Type |
| 214 | +|rel|RELATIONSHIP? |
| 215 | +|=== |
| 216 | + |
| 217 | +=== Usage Examples |
| 218 | + |
| 219 | +The examples in this section are based on the following graph: |
| 220 | + |
| 221 | +[source,cypher] |
| 222 | +---- |
| 223 | +CREATE (p:Person {name: "Billy Reviewer"}) |
| 224 | +CREATE (m:Movie {title:"spooky and goofy movie"}) |
| 225 | +CREATE (p)-[REVIEW {lastSeen: date("1984-12-21")}]->(m); |
| 226 | +---- |
| 227 | + |
| 228 | +This procedure provides a more flexible and performant way of matching relationships than Cypher's https://neo4j.com/docs/cypher-manual/current/clauses/match/[`MATCH`^] clause. |
| 229 | + |
| 230 | +The example below shows equivalent ways of matching an `REVIEW` relationship between the `Billy Reviewer` and a Movie nodes: |
| 231 | + |
| 232 | +// tag::tabs[] |
| 233 | +[.tabs] |
| 234 | + |
| 235 | +.apoc.rel.match |
| 236 | +[source,cypher] |
| 237 | +---- |
| 238 | +MATCH (p:Person {name: "Billy Reviewer"}) |
| 239 | +MATCH (m:Movie {title:"spooky and goofy movie"}) |
| 240 | +CALL apoc.rel.match( |
| 241 | + p, "REVIEW", |
| 242 | + {lastSeen: date("1984-12-21")}, |
| 243 | + m, {rating: 9.5} |
| 244 | +) |
| 245 | +YIELD rel |
| 246 | +RETURN rel; |
| 247 | +---- |
| 248 | + |
| 249 | +.MATCH clause |
| 250 | +[source,cypher] |
| 251 | +---- |
| 252 | +MATCH (p:Person {name: "Billy Reviewer"}) |
| 253 | +MATCH (m:Movie {title:"spooky and goofy movie"}) |
| 254 | +MATCH (p)-[rel:REVIEW {lastSeen: date("1984-12-21")}]->(m) |
| 255 | +SET rel.rating = 9.5 |
| 256 | +RETURN rel; |
| 257 | +---- |
| 258 | +// end::tabs[] |
| 259 | + |
| 260 | +If we run these queries, we'll see output as shown below: |
| 261 | + |
| 262 | +.Results |
| 263 | +[opts="header"] |
| 264 | +|=== |
| 265 | +| rel |
| 266 | +| [:REVIEW {lastSeen: 1984-12-21, rating: 9.5}] |
| 267 | +|=== |
| 268 | + |
| 269 | +But this procedure is mostly useful for matching relationships that have a dynamic relationship type or dynamic properties. |
| 270 | +For example, we might want to match a relationship with a type or properties passed in as parameters. |
| 271 | + |
| 272 | +The following creates `relationshipType` and `properties` parameters: |
| 273 | + |
| 274 | +[source,cypher] |
| 275 | +---- |
| 276 | +:param relType => ("REVIEW"); |
| 277 | +:param identityProperties => ({lastSeen: date("1984-12-21")}); |
| 278 | +---- |
| 279 | + |
| 280 | +The following match a relationship with a type and properties based on the previously defined parameters: |
| 281 | + |
| 282 | +[source,cypher] |
| 283 | +---- |
| 284 | +MATCH (bill:Person {name: "Billy Reviewer"}) |
| 285 | +MATCH (movie:Movie {title:"spooky and goofy movie"}) |
| 286 | +CALL apoc.rel.match(bill, $relType, $identityProperties, movie, {}}) |
| 287 | +YIELD rel |
| 288 | +RETURN rel; |
| 289 | +---- |
| 290 | + |
| 291 | +.Results |
| 292 | +[opts="header"] |
| 293 | +|=== |
| 294 | +| rel |
| 295 | +| [:REVIEW {lastSeen: 1984-12-21, rating: 9.5}] |
| 296 | +|=== |
| 297 | + |
| 298 | + |
| 299 | +In addition, we can use the `apoc.rel.match` along with the `apoc.load.json` to dynamically set nodes starting from a JSON. |
| 300 | + |
| 301 | +For example, given the following dataset: |
| 302 | + |
| 303 | +[source,cypher] |
| 304 | +---- |
| 305 | +CREATE (giacomo:Person:Actor {name: 'Giacomino Poretti'}), |
| 306 | + (aldo:Person:Actor {name: 'Cataldo Baglio'}), |
| 307 | + (m:Movie {title: 'Three Men and a Leg', `y:ear`: 1997, `mean-rating`: 8, `release date`: date('1997-12-27')}) |
| 308 | +WITH aldo, m |
| 309 | +CREATE (aldo)-[:ACTED_IN {role: 'Aldo'}]->(m), |
| 310 | + (aldo)-[:DIRECTED {role: 'Director'}]->(m) |
| 311 | +---- |
| 312 | + |
| 313 | +and the following `all.json` file |
| 314 | +(note that it leverage the elementId of start and end nodes, therefore the values are mutable): |
| 315 | + |
| 316 | +[source,json] |
| 317 | +---- |
| 318 | +[ |
| 319 | + { |
| 320 | + "startNodeId": "4:b3d54d7b-2c64-4994-9a26-0bb2aa175291:0", |
| 321 | + "endNodeId": "4:b3d54d7b-2c64-4994-9a26-0bb2aa175291:0", |
| 322 | + "type":"ACTED_IN", |
| 323 | + "matchProps":{ |
| 324 | + "role":"Aldo" |
| 325 | + }, |
| 326 | + "setProps":{ |
| 327 | + "ajeje":"Brazorf", |
| 328 | + "conte":"Dracula" |
| 329 | + } |
| 330 | + }, |
| 331 | + { |
| 332 | + "startNodeId": "4:b3d54d7b-2c64-4994-9a26-0bb2aa175291:0", |
| 333 | + "endNodeId": "4:b3d54d7b-2c64-4994-9a26-0bb2aa175291:0", |
| 334 | + "type":"DIRECTED", |
| 335 | + "matchProps":{ |
| 336 | + "role":"Director" |
| 337 | + }, |
| 338 | + "setProps":{ |
| 339 | + "description": "did stuff..", |
| 340 | + "alias":"i dunnoaaaaaa" |
| 341 | + } |
| 342 | + } |
| 343 | +] |
| 344 | +---- |
| 345 | + |
| 346 | + |
| 347 | +we can execute the following query to MATCH and SET the relationships: |
| 348 | + |
| 349 | +[source,cypher] |
| 350 | +---- |
| 351 | +CALL apoc.load.json("all.json") YIELD value |
| 352 | +WITH value |
| 353 | +WHERE elementId(start) = value.startNodeId AND elementId(end) = value.endNodeId |
| 354 | +CALL apoc.rel.match(start, value.type, value.matchProps, end, value.setProps) |
| 355 | +YIELD rel |
| 356 | +RETURN rel |
| 357 | +---- |
| 358 | + |
| 359 | +.Results |
| 360 | +[opts="header"] |
| 361 | +|=== |
| 362 | +| rel |
| 363 | +| [:ACTED_IN {role: "Aldo",conte: "Dracula",ajeje: "Brazorf"}] |
| 364 | +| (:Actor:Person {name: "Giovanni Storti",bio: "Giovanni Storti was born ...",Alias: "Rezzonico"}) |
| 365 | +| [:DIRECTED {bio: "did stuff..",alias: "i dunno",role: "Director"}] |
| 366 | +|=== |
0 commit comments