forked from neo4j-contrib/neo4j-apoc-procedures
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes neo4j-contrib#331 - missing detailed documentation for some pro…
…cedures
- Loading branch information
DanielBerton
committed
May 6, 2017
1 parent
83f837e
commit a162e90
Showing
5 changed files
with
356 additions
and
268 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,287 @@ | ||
|
||
[cols="1m,5"] | ||
|=== | ||
| call apoc.refactor.cloneNodes([node1,node2,...]) | clone nodes with their labels and properties | ||
| call apoc.refactor.cloneNodesWithRelationships([node1,node2,...]) | clone nodes with their labels, properties and relationships | ||
| call apoc.refactor.mergeNodes([node1,node2]) | merge nodes onto first in list | ||
| call apoc.refactor.to(rel, endNode) | redirect relationship to use new end-node | ||
| call apoc.refactor.from(rel, startNode) | redirect relationship to use new start-node | ||
| call apoc.refactor.invert(rel) | inverts relationship direction | ||
| call apoc.refactor.setType(rel, 'NEW-TYPE') | change relationship-type | ||
| call apoc.refactor.extractNode([rel1,rel2,...], [labels], 'OUT','IN') | extract node from relationships | ||
| call apoc.refactor.collapseNode([node1,node2],'TYPE') | collapse node to relationship, node with one rel becomes self-relationship | ||
| call apoc.refactor.normalizeAsBoolean(entity, propertyKey, true_values, false_values) | normalize/convert a property to be boolean | ||
| call apoc.refactor.categorize(node, propertyKey, type, outgoing, label) | turn each unique propertyKey into a category node and connect to it | ||
|=== | ||
|
||
TODO: | ||
|
||
* merge nodes by label + property | ||
* merge relationships | ||
=== Graph Refactoring Examples | ||
|
||
.Clone nodes | ||
|
||
We create a dataset | ||
[source,cypher] | ||
---- | ||
CREATE (f:Foo{name:'Foo'}),(b:Bar{name:'Bar'}) | ||
---- | ||
|
||
As result we have two nodes | ||
|
||
image::{img}/apoc.refactor.cloneNodes.dataset.png[width=800] | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Foo{name:'Foo'}),(b:Bar{name:'Bar'}) WITH f,b | ||
CALL apoc.refactor.cloneNodes([f,b]) yield input, output RETURN * | ||
---- | ||
|
||
As result we have the two nodes that we have created before and their clones | ||
|
||
image::{img}/apoc.refactor.cloneNodes.png[width=800] | ||
|
||
.Clone nodes with relationship | ||
|
||
We create a dataset of two different nodes of type `Actor` connected with other two different node of type `Movie` | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (k:Actor {name:'Keanu Reeves'})-[:ACTED_IN {role:'Neo'}]->(m:Movie {title:'The Matrix'}), | ||
(t:Actor {name:'Tom Hanks'})-[:ACTED_IN {role:'Forrest'}]->(f:Movie {title:'Forrest Gump'}) RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.cloneNodesWithRelationships.dataset.png[width=800] | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (k:Actor {name:'Keanu Reeves'}), (t:Actor {name:'Tom Hanks'}) | ||
CALL apoc.refactor.cloneNodesWithRelationships([k,t]) YIELD input, output RETURN * | ||
---- | ||
|
||
As result we have a copy of the nodes and relationships | ||
|
||
image::{img}/apoc.refactor.cloneNodesWithRelationships.png[width=800] | ||
|
||
.Merge nodes | ||
|
||
We create two nodes with different properties | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Person {name:'Foo'}), (b:Person {surname:'Bar'}) RETURN f,b | ||
---- | ||
|
||
image::{img}/apoc.refactor.mergeNodes.dataset.png[width=800] | ||
|
||
Now we want to merge these nodes into one | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Person {name:'Foo'}), (b:Person {surname:'Bar'}) | ||
CALL apoc.refactor.mergeNodes([f,b]) | ||
YIELD node RETURN node | ||
---- | ||
|
||
image::{img}/apoc.refactor.mergeNodes.png[width=800] | ||
|
||
Thus we have one node with both properties `name` and `surname` | ||
|
||
.Redirect relationship to | ||
|
||
We start with two nodes related each other with a relationship. We create a new node which we will use to redirect the relationship like end node | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) | ||
CREATE (p:Person {name:'Antony'}) | ||
RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.to.dataset.png[width=800] | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) with id(rel) as id | ||
MATCH (p:Person {name:'Antony'}) with p as p | ||
MATCH ()-[r]->(), (p:Person) CALL apoc.refactor.to(r, p) YIELD input, output RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.to.png[width=800] | ||
|
||
Now the relationship is towards the new node `Person` | ||
|
||
.Redirect relationship from | ||
|
||
We start with two nodes related each other with a relationship. We create a new node which we will use to redirect the relationship like start node | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) | ||
CREATE (p:Person {name:'Antony'}) | ||
RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.from.dataset.png[width=800] | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) with id(rel) as id | ||
MATCH (p:Person {name:'Antony'}) with p as p | ||
MATCH ()-[r]->(), (p:Person) CALL apoc.refactor.from(r, p) YIELD input, output RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.from.png[width=800] | ||
|
||
Now the relationship starts from the new node `Person` from the old node `Bar` | ||
|
||
.Invert relationship | ||
|
||
We start with two nodes connected by a relationship | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) | ||
---- | ||
|
||
image::{img}/apoc.refactor.invert.dataset.png[width=800] | ||
|
||
Now we want to invert the relationship direction | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) WITH id(rel) as id | ||
MATCH ()-[r]->() WHERE id(r) = id | ||
CALL apoc.refactor.invert(r) yield input, output RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.invert.call.png[width=800] | ||
|
||
image::{img}/apoc.refactor.invert.png[width=800] | ||
|
||
.Set type | ||
|
||
With a simple relationship between two node | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Foo)-[rel:FOOBAR]->(b:Bar) | ||
---- | ||
|
||
image::{img}/apoc.refactor.setType.dataset.png[width=800] | ||
|
||
We can change the relationship type from `FOOBAR` to `NEW-TYPE` | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Foo)-[rel:FOOBAR]->(b:Bar) with rel | ||
CALL apoc.refactor.setType(rel, 'NEW-TYPE') YIELD input, output RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.setType.png[width=800] | ||
|
||
.Extract node from relationships | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) | ||
---- | ||
|
||
image::{img}/apoc.refactor.extractNode.dataset.png[width=800] | ||
|
||
We pass the ID of the relationship as parameter to extract a node | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) WITH id(rel) as id | ||
CALL apoc.refactor.extractNode(id,['FooBar'],'FOO','BAR') | ||
YIELD input, output RETURN * | ||
---- | ||
|
||
image::{img}/apoc.refactor.extractNode.png[width=800] | ||
|
||
.Collapse node to relationship | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (f:Foo)-[:FOO {a:1}]->(b:Bar {c:3})-[:BAR {b:2}]->(f) WITH id(b) as id | ||
CALL apoc.refactor.collapseNode(id,'FOOBAR') | ||
YIELD input, output RETURN * | ||
---- | ||
|
||
Before we have this situation | ||
|
||
image::{img}/apoc.refactor.collapseNode.dataset.png[width=800] | ||
|
||
And the result are | ||
|
||
image::{img}/apoc.refactor.collapseNode.png[width=800] | ||
|
||
The property of the two relationship and the property of the node are joined in one relationship that has the properties `a:1`, `b:2`, `name:Bar` | ||
|
||
.Normalize As Boolean | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (:Person {prop: 'Y', name:'A'}),(:Person {prop: 'Yes', name:'B'}),(:Person {prop: 'NO', name:'C'}),(:Person {prop: 'X', name:'D'}) | ||
---- | ||
|
||
As a resul we have four nodes with different properties `prop` like `Y`, `Yes`, `NO`, `X` | ||
|
||
image::{img}/apoc.refactor.normalizeAsBoolean.dataset.png[width=800] | ||
|
||
Now we want to transform some properties into a boolean, `Y`, `Yes` into true and the properties `NO` into false. | ||
The other properties that don't match these possibilities will be set as `null`. | ||
|
||
[source,cypher] | ||
---- | ||
MATCH (n) CALL apoc.refactor.normalizeAsBoolean(n,'prop',['Y','Yes'],['NO']) WITH n ORDER BY n.id RETURN n.prop AS prop | ||
---- | ||
|
||
image::{img}/apoc.refactor.normalizeAsBoolean.png[width=800] | ||
|
||
.Categorize | ||
|
||
First of all we create some nodes as dataset | ||
|
||
[source,cypher] | ||
---- | ||
CREATE (:Person {prop: 'A', k: 'a', id: 1}), | ||
(:Person {prop: 'A', k: 'a', id: 2}), | ||
(:Person {prop: 'C', k: 'c', id: 3}), | ||
(:Person { id: 4}), | ||
(:Person {prop: 'B', k: 'b', id: 5}), | ||
(:Person {prop: 'C', k: 'c', id: 6}) | ||
---- | ||
|
||
As result we have six nodes with label 'Person' with different properties | ||
|
||
image::{img}/apoc.refactor.categorize.dataset.png[width=800] | ||
|
||
Now we want to transform the property `prop` into a separate node with label `Letter` and transfer the properties of the nodes `Person`: `prop` (now renamed in `name`) and `k`. | ||
The nodes `Person` will keep only the propertie `id`, and will be connected with a relationship `IS_A` with the new nodes `Letter`. | ||
|
||
[source,cypher] | ||
---- | ||
CALL apoc.refactor.categorize('prop','IS_A',true,'Letter','name',['k'],1) | ||
---- | ||
|
||
image::{img}/apoc.refactor.categorize.png[width=800] | ||
|
||
The direction of the relationship (in this case outgoing) is defined by the third field, if `true` outgoing else incoming. | ||
If a node doesn't has the property `prop` (like node with `id: 4`) it won't be managed. | ||
|
||
=== Rename | ||
|
||
Procedures set for renaming labels, relationship types, nodes and relationships' properties. | ||
They return the list of eventually impacted constraints and indexes, the user should take care of. | ||
|
||
[cols="1m,5"] | ||
|=== | ||
| call apoc.refactor.rename.label(oldLabel, newLabel, [nodes]) | rename a label from 'oldLabel' to 'newLabel' for all nodes. If 'nodes' is provided renaming is applied to this set only | ||
| call apoc.refactor.rename.type(oldType, newType, [rels]) | rename all relationships with type 'oldType' to 'newType'. If 'rels' is provided renaming is applied to this set only | ||
| call apoc.refactor.rename.nodeProperty(oldName, newName, [nodes]) | rename all node's property from 'oldName' to 'newName'. If 'nodes' is provided renaming is applied to this set only | ||
| call apoc.refactor.rename.typeProperty(oldName, newName, [rels]) | rename all relationship's property from 'oldName' to 'newName'. If 'rels' is provided renaming is applied to this set only | ||
|=== |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.