Search code examples
c#neo4jcypherneo4jclient

Neo4J - Copy all relationships from one to another node (C# Wrapper)


i'm currently struggling with an issue an i've not found any workaround at the moment. (I'm using NEO4J C# library)

I need to merge two nodes together into a third and copy all the relationships (Type & Properties) from those two nodes to my newly created third node:

(a:Label)-[r]-()
(b:Label)-[r2]-()
(c:Label)

I've been able to properly retrieve my two first nodes & merge it into a third node that's created in the DB, but i'm struggling to copy all relationships from the two firsts nodes to the third one.

I've tried several things without success, such as:

        using (GraphClient graphClient = GetGraphClient())
        {
            var inputString = string.Format("({0}:{1})-[r]->(n), ({2}:{3})", "a", typeof(Label).Name, "b", typeof(Label).Name);
            var query = graphClient.Cypher
                    .SendQueryOnMaster()
                    .Match(inputString)
                    .Where((Label a) => a.Id == from.Id)
                    .AndWhere((Label b) => b.Id == to.Id)
                    .Create("(b)-[r2:type(r)]->(n)");
            query.ExecuteWithoutResults();
        }

Copy all relationships from one node to another might be a use-case people might have encountered :)

Is There any way to make it work ?

Thanks


Solution

  • Update, i've found a way to copy all relationships from one node to another using C# wrapper.

        internal static void DuplicateRelationships<T>(T from, T to) where T : IDataObject
        {
            string aVariable = "a";
            string bVariable = "b";
            string nVariable = "n";
            string relationVariable = "r";
            string newRelation = "r2";
            string relationsVariable = "rels";
            string relationPostCollectVariable = "rel";
    
            Guid fromId = from.Id;
            Guid toId = to.Id;
    
            foreach (string relation in CypherVerbs.GetAllVerbs())
            {
                using (GraphClient graphClient = GetGraphClient())
                {
                    /*-[r]->*/
                    graphClient.Cypher
                        .SendQueryOnMaster()
                        .Match(string.Format("({0}:{1})-[{2}:{3}]->({4}), ({5}:{6})", aVariable, from.GetType().Name, relationVariable, relation, nVariable, bVariable, to.GetType().Name))
                        .Where((T a) => a.Id == fromId)
                        .AndWhere((T b) => b.Id == toId)
                        .With(string.Format("COLLECT({0}) AS {1}, {2}, {3}, {4}", relationVariable, relationsVariable, aVariable, bVariable, nVariable))
                        .ForEach(string.Format("({0} in {1} | ", relationPostCollectVariable, relationsVariable))
                        .Create(string.Format("({0})-[{1}:{2}]->({3})", bVariable, newRelation, relation, nVariable))
                        .Set(string.Format("{0} += {1})", newRelation, relationPostCollectVariable))
                        .ExecuteWithoutResults();
    
                    /*<-[r]-*/
                    graphClient.Cypher
                        .SendQueryOnMaster()
                        .Match(string.Format("({0}:{1})<-[{2}:{3}]-({4}), ({5}:{6})", aVariable, from.GetType().Name, relationVariable, relation, nVariable, bVariable, to.GetType().Name))
                        .Where((T a) => a.Id == fromId)
                        .AndWhere((T b) => b.Id == toId)
                        .With(string.Format("COLLECT({0}) AS {1}, {2}, {3}, {4}", relationVariable, relationsVariable, aVariable, bVariable, nVariable))
                        .ForEach(string.Format("({0} IN {1} | ", relationPostCollectVariable, relationsVariable))
                        .Create(string.Format("({0})<-[{1}:{2}]-({3})", bVariable, newRelation, relation, nVariable))
                        .Set(string.Format("{0} += {1})", newRelation, relationPostCollectVariable))
                        .ExecuteWithoutResults();
                }
            }
        }
    

    Here is the cypher code:

    MATCH (a:Test {props1:"1"}), (b:Test {props3:"3"})
    WITH a,b
    MATCH (a)-[r:LINKED_TO]->(c)
    WITH COLLECT(r) AS rels, a, b, c
    FOREACH (rel in rels |
           CREATE (b)-[r:LINKED_TO]->(c)
           SET r+=rel
    )
    

    EDIT: Since Neo4j 3.0 you can use stored procedure to execute this more efficiently, Michael Hunger developed several template stored procedure including the copy all relationships from one node to another procedure.

    Here is the link to the stored procedure repository: https://github.com/neo4j-contrib/neo4j-apoc-procedures

    Here is the link to the documentation for graph refactoring: https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_graph_refactoring