Question

Is there any way to map params passed in using Merge?

Ideally, this is what I want to do:

Merge node (create if not exists, or update the entire node properties - which are dynamic)

MERGE (c:Label {Id : {map}.Id}) SET c = {map}

This can be done easily when the map is a single object and you are only updating a single node, but I would love to be able to do this as a bulk operation.
Pass in List and have that auto map.

Granted, I don't think this is currently possible using Cypher Merge, but it could be done using the REST API Batch methods, however, it is not clear how to build a batch using Neo4jClient.

If possible, how would one go about building a batch of merge operations? I could enumerate through the List and for each object, add a Merge operation to the batch. Then execute the batch in its entirety.

Any help would be awesome!


Update So, a weird side effect - when I'm running this code:

        createUniqueConstraint(label, PK_Field); 
        string propKey = label + "s" ;

        //string createstr = string.Format("(e:{0} {{{1}}})", label, propKey);
        string strForEach = string.Format("(n in {{{0}}} |  MERGE (c:{1} {{{2} : n.{2}}}) SET c = n)",
            propKey, label, PK_Field);

        foreach (var entities in Neo4jDataRepository.Batch(list, 1000))
        {
            var query = client
                            .Cypher
                            .ForEach(strForEach)
                            .WithParam(propKey, entities.ToList());

            query.ExecuteWithoutResults();
            Debug.WriteLine("Batch passed for " + label + " ("+list.Count()+" items)");
            break;
        }

This works fine (kind of). I have related nodes that also contain a property with the same name as PK_Field, and I end up getting nodes with a single property instead of the entire object.

Example: Contact { ContactId:1,name:"David" } is one model of an object ContactMembership {ContactMembershipId : 1, ContactId: 1, ContactMembershipTypeId: 1} ContactMembershipType {ContactMembershipType: 1, name: "User"}

When running this code, it first loops through each array of Models, and adds / updates the ones in the DB using the Merge statement above. After all the models are in the database, it runs the relationship method call, that takes the relating data model ContactMembership and iterates through that using this code:

 public void CreateNewRelationshipsFromMatrix<T>(IEnumerable<T> relationshipMatrix,   string IDFieldLeft, string IDFieldRight)
        where T : BaseModel
    {
        string entityName = GetTypeName(default(T)); //i.e. ContactAddress

        string merge1 = string.Format("(c:{0} {{{1}:row.{2}}})", IDFieldLeft.Replace("Id", ""), IDFieldLeft, IDFieldLeft);
        string merge2 = string.Format("(a:{0} {{{1}:row.{2}}})", IDFieldRight.Replace("Id", ""), IDFieldRight, IDFieldRight);
        string merge3 = string.Format("(c)-[r:{0}Link]->(a)", entityName);

        string uniqueRelationshipSetter = " ON CREATE SET r.weight=1 ON MATCH SET r.weight = r.weight + 1 ";

        foreach (var list in Neo4jDataRepository.Batch(relationshipMatrix, 1000))
        {
            var q1 = client.Cypher.Merge(merge1);
            var q2 = client.Cypher.Merge(merge2);
            var q3 = client.Cypher.Merge(merge3);

            var query = client
                        .Cypher
                        .WithParam("coll", list.ToList())
                        .ForEach("(row in {coll} | " +
                        q1.Query.QueryText + " " +
                        q2.Query.QueryText + " " +
                        q3.Query.QueryText + ")");
            query.ExecuteWithoutResults();
        }

    }

It seems to be during this second call (the relating of the already existing nodes), that the system creates new nodes with Label :Contact with only the ContactId property and none of the other data. MATCH (n:Contact)-[:ContactMembership]-(t) always returns that ContactId model for n and not the full contact model.

MATCH (n)-[:ContactMembership]-(t) will return the full model for both t and n.

Not sure what is going on here....

Was it helpful?

Solution

FOREACH (n in {set} | MERGE (c:Label {Id : n.Id}) SET c = n)

http://docs.neo4j.org/chunked/stable/query-foreach.html

Update: The other option, coming soon, is that you will be able to write something like this in Cypher:

LOAD CSV WITH HEADERS FROM 'file://c:/temp/input.csv' AS n
MERGE (c:Label { Id : n.Id })
SET c = n

https://github.com/davidegrohmann/neo4j/blob/2.1-fix-resource-failure-load-csv/community/cypher/cypher/src/test/scala/org/neo4j/cypher/LoadCsvAcceptanceTest.scala

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top