0

I am having a problem with my query where the variables defined inside a FOREACH clause is not available to a subsequent MERGE. In the snippet below, I check the existence of a value for each field before I create the Nodes. In some cases these fields can missing, so I don't want to create nodes for them. Then in the last FOREACH, assuming that the reference to those nodes is stored in the variables I try to create their relationships.

FOREACH(ignoreMe IN CASE WHEN "${record:value('/11')}" <> "" THEN [1] ELSE [] END |
  MERGE (company:Company{name:"${record:value('/11')}"}))

FOREACH(ignoreMe IN CASE WHEN "${record:value('/1')}" <> "" THEN [1] ELSE [] END |
  MERGE (cloudSuite:CloudSuite{name:"${record:value('/1')}"}))

FOREACH(ignoreMe IN CASE WHEN "${record:value('/18')}" <> "" THEN [1] ELSE [] END |
  MERGE (application:Application{name:"${record:value('/18')}"}))

FOREACH(ignoreMe IN CASE WHEN "${record:value('/8')}" <> "" THEN [1] ELSE [] END |
  MERGE (applicationInstance:ApplicationInstance{applicationId:"${record:value('/8')}"}))

FOREACH(ignoreMe IN CASE WHEN "${record:value('/9')}" <> "" THEN [1] ELSE [] END |
  MERGE (screen:Screen{name:"${record:value('/9')}"}))

FOREACH(ignoreMe IN CASE WHEN "${record:value('/19')}" <> "" THEN [1] ELSE [] END |
  MERGE (screenInstance:ScreenInstance{screenId:"${record:value('/19')}"}))

FOREACH(ignoreMe IN CASE WHEN ("${record:value('/0')}" IN ["Accessed"])THEN [1] ELSE [] END |
    MERGE (screenInstance)-[:INSTANCE_OF]->(screen)
    MERGE (screenInstance)-[:VIEWED_ON]->(applicationInstance)
    MERGE (application)-[:IMPLEMENTS]->(screen)
    MERGE (session)-[:ACCESSES]->(screenInstance))

However what actually is happening is that when I visualize my graph, I see the valid nodes defined as orphan nodes and the relationships created between some "phantom" nodes. So my question is, if is there a way for me to pass the reference to the valid nodes to the MERGE who creates the relationships.

Cracoras
  • 347
  • 3
  • 16

1 Answers1

1

You won't be able to use this approach, as you discovered variables introduced in FOREACH won't be available outside of it.

You may want to look at using APOC conditional procedures (use the apoc.do.when() proc) in place of the FOREACH workaround. You can return values from the executed Cypher that are exposed via the yielded value map variable.

For example, looking at just the first snippet:

CALL apoc.do.when("${record:value('/11')}" <> "", 
"MERGE (company:Company{name:\"${record:value('/11')}\"}) RETURN company") YIELD value
WITH value.company as company
...

Keep in mind that if a query within a conditional needs to use a variable from outside the conditional, you need to pass it in via the parameter map.

InverseFalcon
  • 29,576
  • 4
  • 38
  • 51
  • Thanks, I changed my query to the following: MERGE (browser:Browser{type:"Chrome"}) ON CREATE SET browser.version="70" WITH browser CALL apoc.do.when("homepages" <> "", "MERGE (application:Application{name:'homepages'}) RETURN application", '') YIELD value WITH value.application AS application MERGE (application)-[:COMPATIBLE_WITH]->(browser), but I end up with 3 nodes. The browser gets created properly, but when linking it to the application node, an empty node is created. It looks like the reference to the browser node is not available on the last MERGE for the relationship. – Cracoras Dec 14 '18 at 18:00
  • You didn't include `browser` in your WITH clause, so it fell out of scope. You need `WITH value.application AS application, browser` – InverseFalcon Dec 14 '18 at 18:57
  • Thanks, that solved the problem. However it raises another question. The relationship is also conditional on the creation or existence of the application node. Is it possible to create the relationship also inside the same ifQuery, (can the ifQuery be made of multiple queries), or would I have to add another call to do.when right after and use the existence of the company node as a condition to create the relationship ? – Cracoras Dec 17 '18 at 14:56