如何使用WITH子句

时间:2019-01-17 16:11:38

标签: neo4j cypher

我有一个很长的Cypher查询,在其中我从文件加载记录并尝试创建节点和关系。文件中可能不存在某些值,因此节点和边的创建必须是有条件的。

我创建了查询的不同部分,并使用WITH语句希望将对节点的引用传递给需要它们创建边的后续语句。

// Mandatory Nodes
MERGE (session:Session{sessionId:"_d6648bbf-f747-42e5-a9b0-adb2cb0aea66-F3AC584AA3E2969240F3E9B285F23C03"})
  ON CREATE SET session.ipAddress="207.54.58.254"
MERGE (user:User {UserId:"dfd75378-a6df-4101-aeb7-fc2f866a75cc"})
MERGE (environment:Environment{server:"qac-portal.qac.awsdev.acme.com", type:"MT"})
MERGE (browser:Browser{type:"Chrome"})
  ON CREATE SET browser.version="70"
MERGE (os:OS{name:"Win10"})
  ON CREATE SET os.version="Win10"
MERGE (device:Device{type:"10.0"})
MERGE (city:City{name:"Atlanta"})
MERGE (country:Country{name:"United States", code:"US"})
MERGE (geoLocation:GeoLocation{latitude:"33.8274", longitude:"-84.3244"})
MERGE (tenant:Tenant{TenantId:"TAMTA1AT2_AX1"})

// Edges between mandatory nodes. 
MERGE (session)-[:ASSIGNED_TO]->(user)
MERGE (session)-[:STARTED_AT]->(geoLocation)
MERGE (geoLocation)-[:COORDINATES_FOR]->(city)
MERGE (city)-[:LOCATED_IN]->(country)
MERGE (session)-[:CONNECTED_WITH]->(browser)
MERGE (browser)-[:RUNS_ON]->(device)
MERGE (browser)-[:SUPPORTS]->(os)
MERGE (os)-[:OPERATES]->(device)
MERGE (environment)-[:HOSTS]->(tenant)

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

// Optional nodes
CALL apoc.do.when(("TAMTA1AT2_AX1" <> ''),
"MERGE (company:Company{name:'TAMTA1AT2_AX1'})",
'', {})
YIELD value AS company

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company
CALL apoc.do.when(("" <> ''),
"MERGE (cloudSuite:CloudSuite{name:''})",
'', {})
YIELD value AS cloudSuite

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite
CALL apoc.do.when(('sample-hr' <> ''),
"MERGE (application:Application{name:'sample-hr'})",
'', {})
YIELD value AS application

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application
CALL apoc.do.when(('lid://acme.sample-hr.ng1' <> ''),
"MERGE (applicationInstance:ApplicationInstance{applicationId:'lid://acme.sample-hr.ng1'})",
'', {})
YIELD value AS applicationInstance

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance
CALL apoc.do.when(('sample-hr_form_Employee_LRCMyGoalsForm' <> ''),
"MERGE (screen:Screen{name:'sample-hr_form_Employee_LRCMyGoalsForm'})",
'', {})
YIELD value AS screen

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen
CALL apoc.do.when(('sample-hr_form_Employee_LRCMyGoalsForm.ng1' <> '' ),
"MERGE (screenInstance:ScreenInstance{screenId:'sample-hr_form_Employee_LRCMyGoalsForm.ng1'})",
'', {})
YIELD value AS screenInstance

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when(((company IS NOT NULL) AND (tenant IS NOT NULL)),
'MERGE (company)-[r:OWNS]->(tenant)', '',{company:company, tenant:tenant}) YIELD value AS owns

// Edges between optional nodes
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant,
     company, cloudSuite, applicationInstance, application, screen, screenInstance
CALL apoc.do.when((("Accessed" = "Accessed") AND (screen IS NOT NULL) AND (screenInstance IS NOT NULL)),
'MERGE (screenInstance)-[r:INSTANCE_OF]->(screen)', '',{screen:screen, screenInstance:screenInstance}) YIELD value AS instanceOf

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when(((application IS NOT NULL) AND (applicationInstance IS NOT NULL)) AND ("Accessed" IN ["Accessed", "Launched", "Entered", "Exited"]),
'MERGE (application)-[r:DEPLOYS]->(applicationInstance)', '',{application:application, applicationInstance:applicationInstance}) YIELD value AS deploys

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when(((application IS NOT NULL) AND (cloudSuite IS NOT NULL)) AND ("Accessed" IN ["Accessed", "Launched", "Entered", "Exited"]),
'MERGE (application)-[r:BELONGS_TO]->(cloudSuite)' , '',{application:application, cloudSuite:cloudSuite}) YIELD value AS belongs_to

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when(((application IS NOT NULL) AND (browser IS NOT NULL)) AND ("Accessed" IN ["Accessed", "Launched", "Entered", "Exited"]),
'MERGE (application)-[r:COMPATIBLE_WITH]->(browser)', '',{application:application, browser:browser}) YIELD value AS compatible_with

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when((("Accessed" = "Accessed") AND (screenInstance IS NOT NULL) AND (applicationInstance IS NOT NULL)),
'MERGE (screenInstance)-[r:VIEWED_ON]->(applicationInstance)', '',{screenInstance:screenInstance, applicationInstance:applicationInstance}) YIELD value AS viewed_on

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when((("Accessed" = "Accessed") AND (application IS NOT NULL) AND (screen IS NOT NULL)),
'MERGE (application)-[:IMPLEMENTS]->(screen)', '',{application:application, screen:screen}) YIELD value AS implements

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.when(((tenant IS NOT NULL) AND (application IS NOT NULL)),
'MERGE (tenant)-[r:PROVISIONED]->(application)', '',{tenant:tenant, application:application}) YIELD value AS provisioned

WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, cloudSuite, application, applicationInstance, screen, screenInstance
CALL apoc.do.case(
[ "Accessed" = "Logged In", "MERGE (session)-[:LOGGED_IN {start='2018-11-06 11:39:10'}]->(applicationInstance)",
  "Accessed" = "Logged Out", "MERGE (session)-[:LOGGED_OUT {end='2018-11-06 11:39:10'}]->(tenant)",
  "Accessed" = "Time Out", "MERGE (session)-[:TIMED_OUT {timeout='2018-11-06 11:39:10'}]->(tenant)",
  "Accessed" = "Accessed", 'MERGE (session)-[:ACCESSED]->(screenInstance)',
  "Accessed" = "Launched", 'MERGE (session)-[:LAUNCHED]->(applicationInstance)',
  "Accessed" = "Entered", 'MERGE (session)-[:ENTERED]->(applicationInstance)',
  "Accessed" = "Exited", 'MERGE (session)-[:EXITED]->(applicationInstance)' ],
'',
{applicationInstance:applicationInstance, screenInstance:screenInstance, session:session, tenant:tenant})
YIELD value AS action
RETURN *

当我在Neo4j浏览器上运行查询时,它将执行并给我以下结果:添加10个标签,创建10个节点,设置16个属性,创建9个关系,并在8毫秒后完成。这意味着并非所有节点都已创建。它实际上完成了前两个部分:“强制性节点和边”,并在创建第一个节点后立即停止:“可选”节点部分中的“公司”。关于这一点,我没有任何线索。我的猜测是我在那里的WITH子句做错了,这带来了我的下一个问题。我必须使用这么多个WITH吗?

在此先感谢您的帮助。

编辑1

感谢解决了“节点”部分的问题:

CALL apoc.do.when(('xxxForm.ng1' <> '' ),
"MERGE (screenInstance:ScreenInstance{screenId:'ljhgjhn-gjhhkjhkhr_form_Employee_LRCMyGoalsForm.ng1'}) RETURN screenInstance",
'', {})
YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, value.application as application, value.company as company, value.cloudSuite as cloudSuite, value.applicationInstance as applicationInstance, value.screen as screen, value.screenInstance as screenInstance

我假设使用相同的方法使用值映射将适用于边缘部分,但是我在那里遇到了相同的问题。此时,地图中的值是否仍然可用?

CALL apoc.do.when(((company IS NOT NULL) AND (tenant IS NOT NULL)),
'MERGE (company)-[r:OWNS]->(tenant) RETURN company, tenant', '',{company:company, tenant:tenant}) YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, value.application as application, value.company as company, value.cloudSuite as cloudSuite, value.applicationInstance as applicationInstance, value.screen as screen, value.screenInstance as screenInstance

CALL apoc.do.when((("Accessed" = "Accessed") AND (screen IS NOT NULL) AND (screenInstance IS NOT NULL)),
'MERGE (screenInstance)-[r:INSTANCE_OF]->(screen) RETURN screenInstance, screen', '',{screen:screen, screenInstance:screenInstance}) YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, value.application as application, value.company as company, value.cloudSuite as cloudSuite, value.applicationInstance as applicationInstance, value.screen as screen, value.screenInstance as screenInstance

编辑2

MERGE (session:Session{sessionId:"_d6648bbf-f747-42e5-a9b0-adb2cb0aea66-F3AC584AA3E2969240F3E9B285F23C03"})
  ON CREATE SET session.ipAddress="207.54.58.254"
WITH session

MERGE (user:User {UserId:"dfd75378-a6df-4101-aeb7-fc2f866a75cc"})
WITH session, user

MERGE (environment:Environment{server:"xxx.yyy.zzz.com", type:"MT"})
WITH session, user, environment

MERGE (browser:Browser{type:"Chrome"})
  ON CREATE SET browser.version="70"
WITH session, user, environment, browser

MERGE (os:OS{name:"Win10"})
  ON CREATE SET os.version="Win10"
WITH session, user, environment, browser, os

MERGE (device:Device{type:"10.0"})
WITH session, user, environment, browser, os, device

MERGE (city:City{name:"Atlanta"})
WITH session, user, environment, browser, os, device, city

MERGE (country:Country{name:"United States", code:"US"})
WITH session, user, environment, browser, os, device, city, country

MERGE (geoLocation:GeoLocation{latitude:"33.8274", longitude:"-84.3244"})
WITH session, user, environment, browser, os, device, city, country, geoLocation

MERGE (tenant:Tenant{TenantId:"TAMTA1AT2_AX1"})
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (session)-[:ASSIGNED_TO]->(user)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (session)-[:STARTED_AT]->(geoLocation)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (geoLocation)-[:COORDINATES_FOR]->(city)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (city)-[:LOCATED_IN]->(country)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (session)-[:CONNECTED_WITH]->(browser)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (browser)-[:RUNS_ON]->(device)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (browser)-[:SUPPORTS]->(os)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (os)-[:OPERATES]->(device)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

MERGE (environment)-[:HOSTS]->(tenant)
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant

// Creating Optional nodes.
CALL apoc.do.when(('sfgsfgn-ghr' <> ''),
"MERGE (application:Application{name:'afasdfn-ghr'}) RETURN application",
'', {})
YIELD value AS mapApplication
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, mapApplication.application as application

CALL apoc.do.when(("TAMTA1AT2_AX1" <> ''),
"MERGE (company:Company{name:'TAMTA1AT2_AX1'}) RETURN company",
'', {})
YIELD value AS mapCompany
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, mapCompany.company as company

CALL apoc.do.when(("" <> ''),
"MERGE (cloudSuite:CloudSuite{name:''}) RETURN cloudSuite",
'', {})
YIELD value AS mapCloudSuite
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, mapCloudSuite.cloudSuite as cloudSuite

CALL apoc.do.when(('lid://afasfafdsghr.ng1' <> ''),
"MERGE (applicationInstance:ApplicationInstance{applicationId:'lid://gfsgsr.ng1'}) RETURN applicationInstance",
'', {})
YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, value.applicationInstance as applicationInstance

CALL apoc.do.when(('lawson-ghr_form_Employee_LRCMyGoalsForm' <> ''),
"MERGE (screen:Screen{name:'lafsafsdfn-ghr_form_Employee_LRCMyGoalsForm'}) RETURN screen",
'', {})
YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, value.screen as screen

CALL apoc.do.when(('sfgfsg-ghr_form_Employee_LRCMyGoalsForm.ng1' <> '' ),
"MERGE (screenInstance:ScreenInstance{screenId:'sgfdn-ghr_form_Employee_LRCMyGoalsForm.ng1'}) RETURN screenInstance",
'', {})
YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, value.screenInstance as screenInstance

// Creating Edges for optional nodes
CALL apoc.do.when(((company IS NOT NULL) AND (tenant IS NOT NULL)),
'WITH company, tenant MERGE (company)-[r:OWNS]->(tenant)', '',{company:company, tenant:tenant}) YIELD value as owns
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when((("Accessed" = "Accessed") AND (screen IS NOT NULL) AND (screenInstance IS NOT NULL)),
'WITH screen, screenInstance MERGE (screenInstance)-[i:INSTANCE_OF]->(screen)', '',{screenInstance:screenInstance, screen:screen}) YIELD value AS instance_of
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when(((application IS NOT NULL) AND (applicationInstance IS NOT NULL)) AND ("Accessed" IN ["Accessed", "Launched", "Entered", "Exited"]),
'WITH application, applicationInstance MERGE (application)-[d:DEPLOYS]->(applicationInstance)', '',{application:application, applicationInstance:applicationInstance}) YIELD value AS deploys
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when(((application IS NOT NULL) AND (cloudSuite IS NOT NULL)) AND ("Accessed" IN ["Accessed", "Launched", "Entered", "Exited"]),
'WITH application, cloudSuite MERGE (application)-[b:BELONGS_TO]->(cloudSuite)' , '',{application:application, cloudSuite:cloudSuite}) YIELD value AS belongs_to
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when(((application IS NOT NULL) AND (browser IS NOT NULL)) AND ("Accessed" IN ["Accessed", "Launched", "Entered", "Exited"]),
"WITH application, browser MERGE (application)-[c:COMPATIBLE_WITH]->(browser)", '',{application:application, browser:browser}) YIELD value AS compatible_with
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when((("Accessed" = "Accessed") AND (applicationInstance IS NOT NULL)),
"WITH screenInstance, applicationInstance MERGE (screenInstance)-[v:VIEWED_ON]->(applicationInstance)", '',{screenInstance:screenInstance, applicationInstance:applicationInstance}) YIELD value AS viewed_on
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when((("Accessed" = "Accessed") AND (application IS NOT NULL) ),
"WITH application, screen MERGE (application)-[i:IMPLEMENTS]->(screen)", '',{application:application, screen:screen}) YIELD value AS implements
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.when(((tenant IS NOT NULL) AND (application IS NOT NULL)),
'WITH tenant, application MERGE (tenant)-[r:PROVISIONED]->(application)', '',{tenant:tenant, application:application}) YIELD value AS provisioned
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, application, company, cloudSuite, applicationInstance, screen, screenInstance

CALL apoc.do.case(
[ "Accessed" = "Logged In", "MERGE (session)-[:LOGGED_IN {start='2018-11-06 11:39:10'}]->(applicationInstance)",
  "Accessed" = "Logged Out", "MERGE (session)-[:LOGGED_OUT {end='2018-11-06 11:39:10'}]->(tenant)",
  "Accessed" = "Time Out", "MERGE (session)-[:TIMED_OUT {timeout='2018-11-06 11:39:10'}]->(tenant)",
  "Accessed" = "Accessed", 'MERGE (session)-[:ACCESSED]->(screenInstance)',
  "Accessed" = "Launched", 'MERGE (session)-[:LAUNCHED]->(applicationInstance)',
  "Accessed" = "Entered", 'MERGE (session)-[:ENTERED]->(applicationInstance)',
  "Accessed" = "Exited", 'MERGE (session)-[:EXITED]->(applicationInstance)' ],
'',
{applicationInstance:applicationInstance, session:session, tenant:tenant})
YIELD value
RETURN *

2 个答案:

答案 0 :(得分:1)

我认为这里最大的问题是使用条件程序时出现了轻微的错误。

如果要返回条件查询中的任何内容,则需要在查询中显式地将其返回。

此外,返回的value是一个包含查询返回的值的映射,它本身不是值。似乎您假设对某件事执行MERGE时,隐式返回了该变量,并且可以通过value对其进行访问,但这是不正确的。正确的用法是这样的:

CALL apoc.do.when(("" <> ''),
"MERGE (cloudSuite:CloudSuite{name:''}) RETURN cloudSuite",
'', {})
YIELD value
WITH session, user, environment, browser, os, device, city, country, geoLocation, tenant, company, value.cloudSuite as cloudSuite, application

在这种情况下,对于所有条件条件用法,在这种情况下需要使用WITH( value.cloudSuite作为cloudSuite )的原因是值映射内派生的变量的别名。

答案 1 :(得分:0)

我发现了问题所在。我没有将变量作为参数传递,而是将结果从过程返回到主查询线程。