Cypher query to take all relationships from one no

2019-04-11 01:31发布

My question is.. given two nodes, node A & node B, is there a cypher query that removes all of the relationships from node A and attaches them instead to node B, so that all nodes that were previously attached to node A, are now attached to node B?

I'm sure there are many use cases for such a query, but my use case is to do with merging multiple social network logins:

Given that I have a member account (member1) using google as a sign in provider And I have a separate member account (member2) using facebook as a sign in provider When member1 attempts to connect to the same facebook account that member2 is using as a sign in provider And member1 requests a merge (merge account) And member2 confirms the merge Then the accounts for member1 and member2 will be merged And one member will be remaining using both google and facebook as a signin provider.

What is the cypher query to do this?

标签: neo4j cypher
3条回答
欢心
2楼-- · 2019-04-11 01:33

EDIT: there is now way, to specify relationship type dynamically. So, workaround below is limited to relationships with same type and with no properties.


Let's create some data:

CREATE (n1:Node1)
CREATE (n2:Node2)
CREATE (target1:Target)
CREATE (target2:Target)
CREATE (target3:Target)
CREATE (n1)-[:REL]->(target1)
CREATE (n1)-[:REL]->(target2)
CREATE (n1)-[:REL]->(target3);

We have such data right now:

data

Now we want to "move" relationship from Node1 to Node2

Query:

MATCH (n1:Node1)-[r:REL]->(target)
MATCH (n2:Node2)
CREATE (n2)-[:REL]->(target)
DELETE r

And result is:

result

What we basically are done is:

  • Get relationship from one path
  • Create relationships to other node
  • Delete relationships from original node
查看更多
聊天终结者
3楼-- · 2019-04-11 01:40

The code for the alternative solution I used is below. I'm having trouble getting the unit tests to run but once they're fixed I'll post a mini project for this on github.

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.server.plugins.Description;
import org.neo4j.server.plugins.Name;
import org.neo4j.server.plugins.Parameter;
import org.neo4j.server.plugins.PluginTarget;
import org.neo4j.server.plugins.ServerPlugin;
import org.neo4j.server.plugins.Source;

/**
 * @author John Deverall
 * This plugin transfers all relationships from one node to another, including the relationships
 * direction, type and properties. 
 * Can be called from the neo4j browser ui with command
 * :POST /db/data/ext/TransferRelationships/graphdb/transfer_relationships {"sourceNode":"/db/data/node/<node_id>", "destinationNode":"/db/data/node/<node_id>"}
 */
public class TransferRelationships extends ServerPlugin {

    @Name("transfer_relationships")
    @Description("Transfer all relationships from one node to another")

    @PluginTarget(GraphDatabaseService.class)
    public Long transferNodes(@Source GraphDatabaseService graphDb,
            @Description("The source node") @Parameter(name = "sourceNode", optional = false) Node sourceNode,
            @Description("The destination node") @Parameter(name = "destinationNode", optional = false) Node destinationNode) {

        try (Transaction tx = graphDb.beginTx()) {
            // transfer outgoing relationships
            Iterable<Relationship> outgoingRelationships = sourceNode.getRelationships(Direction.OUTGOING);
            for (Relationship relationship : outgoingRelationships) {
                Node otherNode = relationship.getOtherNode(sourceNode);
                Relationship newRelationship = destinationNode.createRelationshipTo(otherNode, relationship.getType());

                Iterable<String> propertyKeys = relationship.getPropertyKeys();
                for (String key : propertyKeys) { 
                    Object property = relationship.getProperty(key);
                    newRelationship.setProperty(key, property);
                }

                relationship.delete();
            }

            // transfer incoming relationships
            Iterable<Relationship> incomingRelationships = sourceNode.getRelationships(Direction.INCOMING);
            for (Relationship relationship : incomingRelationships) {
                Node otherNode = relationship.getOtherNode(sourceNode);
                Relationship newRelationship = otherNode.createRelationshipTo(destinationNode, relationship.getType());

                Iterable<String> propertyKeys = relationship.getPropertyKeys();
                for (String key : propertyKeys) { 
                    Object property = relationship.getProperty(key);
                    newRelationship.setProperty(key, property);
                }

                relationship.delete();
            }
            tx.success();
        }
        return destinationNode.getId();
    }
}
查看更多
欢心
4楼-- · 2019-04-11 01:51

I know this thread is old but I googled the same question and didn't found a solution on StackOverflow. So here it is.

As Michael told me here You can use APOC functions :

apoc.refactor.to(relations, destination_node)
apoc.refactor.from(relations, destination_node)

And have something like :

MATCH(n2:Resource {name: 'destionation-resource'})
MATCH(n:Resource {name:'source-resource'})<-[r]-()
OPTIONAL MATCH(n)-[r2]->()
CALL apoc.refactor.to(r, n2) YIELD input, output
CALL apoc.refactor.from(r2, n2) YIELD input AS i, output AS o
RETURN *
查看更多
登录 后发表回答