refactor

The refactor module provides utilities for changing nodes and relationships.

docs-source (opens in a new tab)

TraitValue
Module typealgorithm
ImplementationC++
Parallelismsequential

Procedures

from(relationship, new_from)

Redirect the relationship to use a new start (from) node.

Input:

  • relationship: Relationship ➡ the relationship to be modified.
  • new_from: Node ➡ new start (from) node.

Output:

  • relationship - the modified relationship.

Usage:

MERGE (ivan:Person {name: "Ivan"}) MERGE (matija:Person {name: "Matija"}) MERGE (diora:Person {name:"Idora"}) CREATE (ivan)-[:Friends]->(matija);

The following query changes the the relationship Ivan ➡ Matija to Idora ➡ Matija.

MATCH (:Person {name: "Ivan"})-[rel:Friends]->(:Person {name: "Matija"}) MATCH (idora: Person {name:"Idora"}) CALL refactor.from(rel, idora) YIELD relationship RETURN relationship;

to(relationship, new_to)

Redirect the relationship to use a new end (to) node.

Input:

  • relationship: Relationship ➡ the relationship to be modified.
  • new_to: Node ➡ new end (to) node.

Output:

  • relationship - the modified relationship.

Usage:

MERGE (ivan:Person {name: "Ivan"}) MERGE (matija:Person {name: "Matija"}) MERGE (diora:Person {name:"Idora"}) CREATE (ivan)-[:Friends]->(matija);

The following query changes the the relationship Ivan ➡ Matija to Ivan ➡ Idora.

MATCH (:Person {name: "Ivan"})-[rel:Friends]->(:Person {name: "Matija"}) MATCH (idora: Person {name:"Idora"}) CALL refactor.to(rel, idora) YIELD relationship RETURN relationship;

rename_label(old_label, new_label, nodes)

Rename a label from old_label to new_label for all nodes. If nodes is provided renaming is applied only to the given nodes. If a node doesn't contain the old_label the procedure doesn't modify it.

Input:

  • old_label: str ➡ old label name.
  • new_label: str ➡ new label name.
  • nodes: List[Node] ➡ list of nodes to be modified.

Output:

  • nodes_changed: int ➡ number of modified nodes.

Usage:

CREATE (:Node1 {title: "Node1"}) CREATE (:Node2 {title: "Node2"}) CREATE (:Node1);

The following query changes the label of the first node to Node

MATCH(n) WITH collect(n) AS nodes CALL refactor.rename_label("Node1", "Node3", nodes) YIELD nodes_changed RETURN nodes_changed;
+----------------------------+
| nodes_changed              |
+----------------------------+
|    2                       |
+----------------------------+

rename_node_property(old_property, new_property, nodes)

Rename a property from old_property to new_property for all nodes. If nodes is provided renaming is applied only to the given nodes. If a node doesn't contain the old_property the procedure doesn't modify it.

Input:

  • old_property: str ➡ old property name.
  • new_label: str ➡ new property name.
  • nodes: List[Node] ➡ list of nodes to be modified.

Output:

  • nodes_changed: int ➡ number of modified nodes.

Usage:

CREATE (:Node1 {title: "Node1"}) CREATE (:Node2 {description: "Node2"}) CREATE (:Node3) CREATE (:Node4 {title: "title", description: "description"});

The following query will modify Node1 and Node4.

MATCH(n) WITH collect(n) AS nodes CALL refactor.rename_node_property("title", "description", nodes) YIELD nodes_changed RETURN nodes_changed;
+----------------------------+
| nodes_changed              |
+----------------------------+
|    2                       |
+----------------------------+

categorize(original_prop_key, rel_type, is_outgoing, new_label, new_prop_name_key, copy_props_list)

Generates a new category of nodes based on a specific property key from the existing nodes in the graph. Then, it creates relationships between the original and new category nodes to organize a graph based on these categories.

Input:

  • original_prop_key: string ➡ the property key on the existing nodes used to determine the category.
  • rel_type: string ➡ the type of relationship to be created between the original nodes and the new category nodes.
  • is_outgoing: bool ➡ determines the direction of the new relationships. If 'true', relationships will be created from the original node to the category node. If 'false', they'll be created from the category node to the original node.
  • new_label: string ➡ the label to be assigned to the new category nodes.
  • new_prop_name_key: string ➡ the key for the new category node's property whose value will be the same as original_prop_key value.
  • copy_props_list: List[string] (default = []) ➡ an array of property keys from the original nodes to be copied to the new category nodes.

Output:

  • status: string ➡ "success" if no errors were generated.

Usage:

CALL refactor.categorize('genre', 'GENRE', false, "Genre", "name") YIELD status RETURN status;
+----------------------------+
| status                     |
+----------------------------+
| success                    |
+----------------------------+

Example:

You can create a simple graph database by running the following queries:

CREATE (a:Movie {id: 0, name: "MovieName", genre: "Drama"})
CREATE (b:Book {id: 1, name: "BookName1", genre: "Drama", propertyToCopy: "copy me"})
CREATE (c:Book {id: 2, name: "BookName2", genre: "Romance"});

The image below shows the above data as a graph:

CALL refactor.categorize('genre', 'GENRE', true, "Genre", "name", ["propertyToCopy"]) 
YIELD status RETURN status;

The results should be identical to the ones in the graph below, except for the id values, which depend on the internal database id values:

clone_nodes(nodes, clone_rels, skip_props)

Clones specific nodes in the graph, preserving their original labels, properties and optionally relationships. Offers the flexibility to exclude specific node properties during the cloning process.

Input:

  • nodes: List[Node] ➡ a list of nodes intended for duplication.
  • clone_rels: bool (default = false) ➡ if set to true, the function will also clone the relationships of the original nodes, connecting them to the cloned nodes in the same manner.
  • skip_props: List[string] (default = []) ➡ a list of property keys, properties associated with these keys will be skipped during the cloning process.

Output:

  • cloned_node_id: int ➡ ID of the original node which was cloned.
  • new_node: Node ➡ new cloned node.

Usage:

MATCH (a:Person {name: "Ana", age: 22, id:0})
CALL refactor.clone_nodes([a], False, ["age", "id"]) 
YIELD cloned_node_id, new_node RETURN cloned_node_id, new_node;
+----------------------------+----------------------------+
| cloned_node_id             | new_node                   |
+----------------------------+----------------------------+
| 0                          | {                          |
|                            |     "id": 1,               |
|                            |     "labels": [            |
|                            |        "Person"            |
|                            |     ],                     |
|                            |     "properties": {        |
|                            |        name: "Ana"         |
|                            |     },                     |
|                            |     "type": "node"         |
|                            | }                          |
+----------------------------+----------------------------+

Example:

You can create a simple graph database by running the following queries:

CREATE (a:Ana {name: "Ana", age: 22}) 
CREATE (b:Marija {name: "Marija", age: 20}) 
CREATE (a)-[r:KNOWS]->(b);

The image below shows the above data as a graph:

MATCH (a:Ana) MATCH (b:Marija)
CALL refactor.clone_nodes([a, b], True, ["age"]) YIELD * RETURN *;

The results should be identical to the ones in the graph below, except for the id values, which depend on the internal database id values:

clone_subgraph(nodes, rels, config)

Clones the subgraph by cloning the given list of nodes and relationships. If no relationships are provided, all existing relationships between the given nodes will be cloned.

Input:

  • nodes: List[Node] ➡ a list of nodes which form the subgraph intended for duplication.
  • rels: List[Relationship] (default = []) ➡ a list of relationships intended for duplication. If this list is empty or not provided, all existing relationships between the given nodes will be cloned.
  • config: Map (default = {}) ➡ configuration parameters explained below.

Parameters:

NameTypeDefaultDescription
skipPropertiesList[ ]A list of property keys. Properties associated with these keys will be skipped during the cloning process. Therefore, new nodes will not have them.
standinNodesList[ ]A list of pairs (lists with only two elements) where: 1) The first element is the original node (from the input nodes list) that you're planning to clone. 2) The second element is an existing node in the graph that will "stand in" or replace the clone of the original node in the resultant subgraph.

Output:

  • cloned_node_id: int ➡ ID of the original node which was cloned.
  • new_node: Node ➡ new cloned node.

Usage:

MATCH (ana:Ana {id: 0}), (marija:Marija {id: 1})
MATCH (ana)-[r1:KNOWS]->(marija)
CALL refactor.clone_subgraph([ana, marija], [r1], {standinNodes: [[ana, marija]]})
YIELD cloned_node_id, new_node RETURN cloned_node_id, new_node;
+----------------------------+----------------------------+
| cloned_node_id             | new_node                   |
+----------------------------+----------------------------+
| 1                          | {                          |
|                            |     "id": 2,               |
|                            |     "labels": [            |   -> node :Ana was not cloned
|                            |        "Marija"            |      because :Marija is its
|                            |     ],                     |      "stand-in" node
|                            |     "properties": {},      |
|                            |     "type": "node"         |
|                            | }                          |
+----------------------------+----------------------------+

Example:

You can create a simple graph database by running the following queries:

MERGE (ana:Ana{name:'Ana'}) 
MERGE (marija:Marija{name:'Marija'}) 
MERGE (p2:Person{name:'person2'}) 
MERGE (p3:Person{name:'person3'}) 
MERGE (p4:Person{name:'person4'}) 
MERGE (p5:Person{name:'person5'}) 
MERGE (p6:Person{name:'person6'}) 
CREATE (ana)-[:KNOWS]->(p2)-[:KNOWS]->(p3)-[:KNOWS]->(p4) 
CREATE (p4)<-[:KNOWS]-(p5) 
CREATE (marija)-[:KNOWS]->(p6);

The image below shows the above data as a graph:

MATCH (ana:Ana),
      (p2:Person{name: "person2"}),     
      (p3:Person{name: "person3"}),
      (p4:Person{name: "person4"}),
      (p5:Person{name: "person5"})
CALL refactor.clone_subgraph([ana, p2, p3, p4, p5], [], {
       standinNodes:[[ana, marija]]
   })
YIELD * RETURN *;

The results should be identical to the ones in the graph below, except for the id values, which depend on the internal database id values. Note that the whole subgraph was cloned except for node :Ana because node :Marija was used as its "stand-in" node.

clone_subgraph_from_paths(paths, config)

Clones the subgraph specified by a specific list of paths. A path is a series of nodes connected by relationships.

Input:

  • paths: List[Path] ➡ a list of paths which define the subgraph intended for duplication.
  • config: Map (default = {}) ➡ configuration parameters explained below.

Parameters:

NameTypeDefaultDescription
skipPropertiesList[ ]A list of property keys. Properties associated with these keys will be skipped during the cloning process. Therefore, new nodes will not have them.
standinNodesList[ ]A list of pairs (lists with only two elements) where the first element is the original node (from the input nodes list) that you're planning to clone, and the second element is an existing node in the graph that will "stand-in" or replace the clone of the original node in the resultant subgraph.

Output:

  • cloned_node_id: int ➡ ID of the original node which was cloned.
  • new_node: Node ➡ new cloned node.

Usage:

MATCH (ana:Ana {id: 0}), (marija:Marija {id: 1})
MATCH path = (ana)-[:KNOWS*]->(marija)
CALL refactor.clone_subgraph_from_paths([path], {standinNodes:[[ana, marija]]})
YIELD cloned_node_id, new_node RETURN cloned_node_id, new_node;
+----------------------------+----------------------------+
| cloned_node_id             | new_node                   |
+----------------------------+----------------------------+
| 1                          | {                          |
|                            |     "id": 2,               |
|                            |     "labels": [            |   -> node :Ana was not cloned
|                            |        "Marija"            |      because :Marija is its
|                            |     ],                     |      "stand-in" node
|                            |     "properties": {},      |
|                            |     "type": "node"         |
|                            | }                          |
+----------------------------+----------------------------+

Example:

You can create a simple graph database by running the following queries:

MERGE (ana:Ana{name:'Ana'}) 
MERGE (marija:Marija{name:'Marija'}) 
MERGE (p2:Person{name:'person2'}) 
MERGE (p3:Person{name:'person3'}) 
MERGE (p4:Person{name:'person4'}) 
MERGE (p5:Person{name:'person5'}) 
MERGE (p6:Person{name:'person6'}) 
CREATE (ana)-[:KNOWS]->(p2)-[:KNOWS]->(p3)-[:KNOWS]->(p4) 
CREATE (p4)<-[:KNOWS]-(p5) CREATE (p5)-[:LOVES]->(p6) 
CREATE (marija)-[:KNOWS]->(p6);

The image below shows the above data as a graph:

MATCH (ana:Ana),
      (marija:Marija)
MATCH path = (ana)-[:KNOWS*]->(node)
WITH ana, marija, collect(path) as paths
CALL refactor.clone_subgraph_from_paths(paths, {
       standinNodes:[[ana, marija]]
})
YIELD cloned_node_id, new_node
RETURN cloned_node_id, new_node;

The results should be identical to the ones in the graph below, except for the id values, which depend on the internal database id values. Note that the whole subgraph was cloned except for the node :Ana because node :Marija was used as its "stand-in" node.

collapse_node(nodes, type)

Collapses a node into a relationship. Can only collapse nodes with exactly 1 in relationship, and exactly 1 out relationship. The node must not have any self relationships. Collapsing any node that doesn't satisfy these requirements results in an exception.

Input:

  • nodes: Any ➡ a node, node ID, or list of nodes and node IDs.
  • type: string ➡ the type of the new relationship.

Output:

  • id_collapsed: integer ➡ ID of the collapsed node.
  • new_relationship: integer ➡ newly created relationship.

Usage:

Create the following graph:

CREATE (c:Car)-[t:DRIVES_ON]->(r:Road)-[l:LEADS_TO]->(ci:City);

Run the refactor.collapse_node() procedure:

MATCH (r:Road)
CALL refactor.collapse_node(r, "DRIVES_TO") YIELD id_collapsed, new_relationship RETURN id_collapsed, new_relationship;
+-------------------------------------------------------------------------------------------------------------------+
| id_collapsed        | new_relationship                                                                            |
+-------------------------------------------------------------------------------------------------------------------+
| 1                   | {"id": 2,"start": 0,"end": 2,"label": "DRIVES_TO","properties": {},"type": "relationship"}  |
+-------------------------------------------------------------------------------------------------------------------+

invert(relationship)

Invert the direction of the given relationship.

Input:

  • relationship: Any ➡ relationship, relationship ID, or a list of relationships or relationship IDs.

Output:

  • id_inverted: integer ➡ ID of the inverted relationship.
  • relationship ➡ the inverted relationship.

Usage:

Create the following graph:

CREATE (d:Dog)-[l:LOVES]->(h:Human);

Run the refactor.invert() procedure:

MATCH (d:Dog)-[l:LOVES]->(h:Human)
CALL refactor.invert(l) YIELD id_inverted, relationship RETURN id_inverted, relationship;
+-------------------------------------------------------------------------------------------------------------------+
| id_inverted         | relationship                                                                                |
+-------------------------------------------------------------------------------------------------------------------+
| 0                   | {"id": 0,"start": 1,"end": 0,"label": "LOVES","properties": {},"type": "relationship"}      |
+-------------------------------------------------------------------------------------------------------------------+