chickenmagician
chickenmagician

Reputation: 23

Creating relationship with name as a variable. (RDBMS to Neo4J migration)

I'm trying to migrate our current data set to Neo4J and was fairly successful so far until I reach this problem. I'm trying to create a set of relationships between 2 node where the name of the relationship is a variable. In my MySQL database, I have Role object which map to a pair of (Resource, Action) so I'm trying to convert it to Neo4J with data model such as (Role)-[Action]->(Resource). This is what I have but this doesn't seem like valid syntax:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///roletoresourceaction.csv" AS row
MATCH (role:Role {roleId: row.ROLE_ID})
MATCH (resource:Resource {resourceId: row.RESOURCE_ID})
MATCH (action:Action {actionId: row.ACTION_ID})
MERGE (role)-[r:action.name]->(roleAsResource)

Would appreciate any help on this. Thanks.

Upvotes: 1

Views: 1787

Answers (2)

cybersam
cybersam

Reputation: 66989

Neo4j 3.x added support for apoc procedures (which must be installed on the server before they can be used).

With the apoc procedure apoc.create.relationship, you should be able to do the equivalent of a MERGE of dynamic relationship types. The Cypher language, by itself, only supports the creation/merging of static relationship types.

Hopefully, this works for you:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///roletoresourceaction.csv" AS row
MATCH
  (role:Role {roleId: row.ROLE_ID}),
  (resource:Resource {resourceId: row.RESOURCE_ID}),
  (action:Action {actionId: row.ACTION_ID})
OPTIONAL MATCH (role)-[rel]->(resource)
WITH role, resource, action, COLLECT(TYPE(rel)) AS relTypes
WHERE NOT action.name IN relTypes
CALL apoc.create.relationship(role, action.name, NULL, resource) YIELD newRel
RETURN role, resource, newRel;

The OPTIONAL MATCH and WHERE clauses verify that the relationship does not already exist before allowing apoc.create.relationship to create it.

ASIDE: I was also hoping to use the apoc.path.expand procedure instead of the OPTIONAL MATCH clause (with some additional changes), but that procedure currently seems to abort the query when it fails to find a match -- even testing the returned path for NULL does not help.

Upvotes: 1

chickenmagician
chickenmagician

Reputation: 23

This solution worked for me

LOAD CSV WITH HEADERS FROM "file:///roletoresourceaction.csv" AS row
MATCH
  (role:Role {roleId: row.ROLE_ID}),
  (resource:Resource {resourceId: row.RESOURCE_ID}),
  (action:Action {actionId: row.ACTION_ID})
OPTIONAL MATCH (role)-[rel]->(resource)
WITH role, resource, action, COLLECT(TYPE(rel)) AS relTypes
WHERE NOT action.name IN relTypes
CALL apoc.create.relationship(role, action.name, NULL, resource)      YIELD rel
RETURN role, resource, rel;

Upvotes: 0

Related Questions