Clone subgraph

The APOC library contains procedures that can be used to clone subgraphs. These procedures can be used to clone a subgraph defined either by a list of nodes and a list of relationships, or a list of paths. This is useful when you want to ensure the cloned subgraph is not connected to the original nodes, or to nodes outside the subgraph.

If relationships are not provided, all relationships between the given nodes will be cloned. In the config map, a list of standinNodes (of pairs of nodes) can be provided, allowing an existing node in the graph to act as a standin for another node in the cloned subgraph. This can be useful for attaching the cloned subgraph to another node in the graph (rather than cloning a node).

Procedures for cloning subgraphs

Qualified Name Type

apoc.refactor.cloneSubgraph(nodes LIST<NODE>, rels LIST<RELATIONSHIP>, config MAP<STRING, ANY>) - clones the given NODE values with their labels and properties (optionally skipping any properties in the skipProperties LIST<STRING> via the config MAP), and clones the given RELATIONSHIP values. If no RELATIONSHIP values are provided, all existing RELATIONSHIP values between the given NODE values will be cloned.

Procedure

apoc.refactor.cloneSubgraphFromPaths(paths LIST<PATH>, config MAP<STRING, ANY>) - clones a sub-graph defined by the given LIST<PATH> values. It is possible to skip any NODE properties using the skipProperties LIST<STRING> via the config MAP.

Procedure

Examples

The examples below will further explain these procedures.

The following creates a dataset containing two trees:
CREATE  (rootA:Root{name:'A'}),
        (rootB:Root{name:'B'}),
        (n1:Node{name:'node1', id:1}),
        (n2:Node{name:'node2', id:2}),
        (n3:Node{name:'node3', id:3}),
        (n4:Node{name:'node4', id:4}),
        (n5:Node{name:'node5', id:5}),
        (n6:Node{name:'node6', id:6}),
        (n7:Node{name:'node7', id:7}),
        (n8:Node{name:'node8', id:8}),
        (n9:Node{name:'node9', id:9}),
        (n10:Node{name:'node10', id:10}),
        (n11:Node{name:'node11', id:11}),
        (n12:Node{name:'node12', id:12})
        CREATE (rootA)-[:LINK]->(n1)-[:LINK]->(n2)-[:LINK]->(n3)-[:LINK]->(n4)
        CREATE                  (n1)-[:LINK]->(n5)-[:LINK]->(n6)<-[:LINK]-(n7)
        CREATE                                (n5)-[:LINK]->(n8)
        CREATE                                (n5)-[:LINK]->(n9)-[:DIFFERENT_LINK]->(n10)
        CREATE (rootB)-[:LINK]->(n11)
apoc.refactor.cloneSubgraph tree example
The following query clones a subtree starting from rootA consisting of outgoing :LINK relationships, and attaches that subgraph to rootB. rootB acts as a standin for rootA, which is not cloned:
MATCH  (rootA:Root{name:'A'}),
       (rootB:Root{name:'B'})
MATCH path = (rootA)-[:LINK*]->(node)
WITH rootA, rootB, collect(path) as paths
CALL apoc.refactor.cloneSubgraphFromPaths(paths, {
    standinNodes:[[rootA, rootB]]
})
YIELD input, output, error
RETURN input, output, error

If the above query is run, it will result in the following graph:

apoc.refactor.cloneSubgraph tree example after

Another approach is to use apoc.refactor.cloneSubgraph(), providing the lists of nodes and relationships which form the subgraph. The nodes and relationships from the yielded output can be obtained using apoc.path.subgraphAll(), filtering to the relationship types in the call to that procedure.

The following query creates a dataset containing two trees:
CREATE  (rootA:Root2{name:'A'}),
        (rootB:Root2{name:'B'}),
        (n1:Node2{name:'node1', id:1}),
        (n2:Node2{name:'node2', id:2}),
        (n3:Node2{name:'node3', id:3}),
        (n4:Node2{name:'node4', id:4}),
        (n5:Node2{name:'node5', id:5}),
        (n6:Node2{name:'node6', id:6}),
        (n7:Node2{name:'node7', id:7}),
        (n8:Node2{name:'node8', id:8}),
        (n9:Node2{name:'node9', id:9}),
        (n10:Node2{name:'node10', id:10}),
        (n11:Node2{name:'node11', id:11}),
        (n12:Node2{name:'node12', id:12})
        CREATE (rootA)-[:LINK]->(n1)-[:LINK]->(n2)-[:LINK]->(n3)-[:LINK]->(n4)
        CREATE                  (n1)-[:LINK]->(n5)-[:LINK]->(n6)<-[:LINK]-(n7)
        CREATE                                (n5)-[:LINK]->(n8)
        CREATE                                (n5)-[:LINK]->(n9)-[:DIFFERENT_LINK]->(n10)
        CREATE (rootB)-[:LINK]->(n11)
The following query clones a subtree starting from rootA consisting of outgoing :LINK relationships, and attaches that subgraph to rootB. rootB acts as a standin for rootA, which is not cloned:
MATCH  (rootA:Root2{name:'A'}),
       (rootB:Root2{name:'B'})
CALL apoc.path.subgraphAll(rootA, {relationshipFilter:'LINK>'})
YIELD nodes, relationships
CALL apoc.refactor.cloneSubgraph(
    nodes,
    [rel in relationships WHERE type(rel) = 'LINK'],
    { standinNodes:[[rootA, rootB]] })
YIELD input, output, error
RETURN input, output, error

The resulting graph will be the same as that returned in the previous example, where apoc.refactor.cloneSubgraphFromPaths() was called.