Neo4j: Creating nodes and relationships from a list of maps
Date: 2014-02-17 14:11:07

Last week https://twitter.com/apcj[Alistair] and I were porting some Neo4j cypher queries from 1.8 to 2.0 and one of the queries we had to change was an interesting one that created a bunch of relationships from a list/array of maps.

In the query we had a user 'Mark' and wanted to create 'FRIENDS_WITH' relationships to Peter and Michael.

image::{{<siteurl>}}/uploads/2014/02/2014-02-17_13-39-08.png[2014 02 17 13 39 08,600]

The application passed in a list of maps representing Peter and Michael as a parameter but if we remove the parameters the query looked like this:

[source,cypher]
----

MERGE (me:User {userId: 1} )
SET me.name = "Mark"
FOREACH (f IN [{userId: 2, name: "Michael"}, {userId: 3, name: "Peter"}] |
    MERGE (u:User {userId: f.userId})
    SET u = f
    MERGE (me)-[:FRIENDS_WITH]->(u))
----

We first ensure that a user with 'id' of 1 exists in the database and then make sure their name is set to 'Mark'. After we've done that we iterate over a list of maps containing Mark's friends and ensure there is a 'FRIENDS_WITH' relationship from Mark to them.

The parameterised version of that query looks like this:

[source,cypher]
----

MERGE (me:User { userId: {userId} })
SET me.name = {name}
FOREACH(f IN {friends} |
    MERGE (u:User {userId: f.userId })
    SET u = f
    MERGE (me)-[:FRIENDS_WITH]->(u))
----

We can then execute that query using Jersey:

[source,java]
----

public class ListsOfMapsCypher
{
    public static void main( String[] args )
    {
        ObjectNode request = JsonNodeFactory.instance.objectNode();
        request.put("query",
                "MERGE (me:User { userId: {userId} }) " +
                "SET me.name = {name} " +
                "FOREACH(f IN {friends} | " +
                    "MERGE (u:User {userId: f.userId }) " +
                    "SET u = f " +
                    "MERGE (me)-[:FRIENDS_WITH]->(u)) ");

        ObjectNode params = JsonNodeFactory.instance.objectNode();
        params.put("userId", 1);
        params.put("name", "Mark");

        ArrayNode friends = JsonNodeFactory.instance.arrayNode();

        ObjectNode friend1 = JsonNodeFactory.instance.objectNode();
        friend1.put( "userId", 2 );
        friend1.put( "name", "Michael" );
        friends.add( friend1 );

        ObjectNode friend2 = JsonNodeFactory.instance.objectNode();
        friend2.put( "userId", 3 );
        friend2.put( "name", "Peter" );
        friends.add( friend2 );

        params.put("friends", friends );

        request.put("params", params );

        ClientResponse clientResponse = client()
                .resource( "http://localhost:7474/db/data/cypher" )
                .accept( MediaType.APPLICATION_JSON )
                .entity( request, MediaType.APPLICATION_JSON_TYPE )
                .post( ClientResponse.class );


        System.out.println(clientResponse.getEntity( String.class ));
    }

    private static Client client()
    {
        DefaultClientConfig defaultClientConfig = new DefaultClientConfig();
        defaultClientConfig.getClasses().add(JacksonJsonProvider.class);
        return Client.create(defaultClientConfig);
    }
}
----

We can then write a query to check Mark and his friends were persisted:

image::{{<siteurl>}}/uploads/2014/02/2014-02-17_14-10-12.png[2014 02 17 14 10 12,600]

And that's it!