【问题标题】:Cypher Neo4J - CASE Expression with MERGECypher Neo4J - 使用 MERGE 的 CASE 表达式
【发布时间】:2015-02-19 00:03:06
【问题描述】:

我正在尝试在 Cypher 中实现逻辑,根据特定条件(CASE 语句),我将创建一些节点和关系;代码如下

MATCH (g:Game)-[:PLAYER]->(u:User)-[r1:AT]->(b1:Block)-[:NEXT]->(b2:Block) 
WHERE g.game_id='G222' and u.email_id = 'xyz@example.com' and b1.block_id='16' 
SET r1.status='Skipped', r1.enddate=20141225
WITH u, b2,b1, g, r1
SET b1.test = CASE b2.fork 
WHEN 'y' THEN
     MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2     {fork:'fail'}) RETURN 1
ELSE 
     MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2)   RETURN 2
END
WITH u, g
MATCH (u)-[:TIME]->(h:Time)<-[:TIME]-(g)
SET h.after = 0
SET h.before = h.before + 1

在这个查询中,WHEN 'y' THEN 中有一个merge 语句,这个查询抛出一个错误:

无效的输入“]”:预期的空白或关系模式(第 7 行,第 82 列) "合并 (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'}) 返回 1"

基本上,我正在尝试基于属性(即CASE 语句中的MERGE)创建关系,我尝试了不同的方法来使其正常工作,例如返回,以便在返回某些值等情况下进行。到目前为止没有任何效果。

这个查询可能有什么问题?

【问题讨论】:

    标签: merge neo4j logic case cypher


    【解决方案1】:

    要执行条件写入操作,您需要使用FOREACH 技巧。使用 CASE 您可以返回一个元素数组或一个空数组。 FOREACH 迭代 CASE 表达式,因此有条件地执行操作。如果您还想要一个ELSE 部分,则需要使用CASE 中的逆条件来创建另一个FOREACH。例如,而不是

    WHEN 'y' THEN
       MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2     {fork:'fail'}) RETURN 1
    ELSE 
        MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2)   RETURN 2
    END
    

    使用

    FOREACH(ignoreMe IN CASE WHEN 'y' THEN [1] ELSE [] END | 
        MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'})
    )
    FOREACH(ignoreMe IN CASE WHEN NOT 'y' THEN [1] ELSE [] END | 
        MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2)
    )
    

    另请参阅Mark's blog post

    【讨论】:

    • 谢谢Stefan,是的,你是对的,看来我们需要使用FOREACH,我还参考了你之前在StackOverflow中的一篇文章,逻辑最终是这样的 WITH u, b2,b1, g , r1, CASE WHEN (b1.fork='y' and b2.fork='success') or (b1.fork='n') or (b1.fork='success') THEN ['ok'] ELSE [ ] END as array1 FOREACH (el1 in array1 | MERGE (u)-[r2:STAGE {startdate:20141225, enddate:99999999, status:'InProgress'}]->(b2))
    • 好戏,但你能解释一下THEN [1] ELSE []是什么意思,ignoreMe是什么意思(对不起,我不能忽略你)?跨度>
    • Cypher 没有更新让我们忘记这个黑客?我真的很想知道,这个回复在 2018 年已经过时了。
    • @HerrIvan 这仍然是有条件合并的唯一方法吗?
    • @bigmadwolf:是的。这是我一年前的问题。但从那以后就没有答案了……也许 Stefan Armbruster 知道得更清楚。
    【解决方案2】:

    修复如下问题

    WITH u, b2,b1, g, r1, CASE  WHEN (b1.fork='y' and b2.fork='success') or (b1.fork='n') or   (b1.fork='success') THEN ['ok'] ELSE [] END as array1
    FOREACH (el1 in array1 | MERGE (u)-[r2:STAGE {startdate:20141225, enddate:99999999, status:'InProgress'}]->(b2))
    

    即使用 CASE WHEN 创建一个虚拟数组,该数组在某种程度上具有与匹配计数匹配的虚拟元素,然后使用 FOREACH 遍历结果。

    再次感谢 Stefan 的创意...

    深度学习

    【讨论】:

    • 不把长长的业务逻辑放到CQL里面会更整洁。
    【解决方案3】:

    APOC 插件支持Conditional Cypher Execution,现在我们可以避免使用FOREACH 解决方法。

    例如,您可以这样做:

    MATCH (g:Game)-[:PLAYER]->(u:User)-[r1:AT]->(b1:Block)-[:NEXT]->(b2:Block) 
    WHERE g.game_id='G222' AND u.email_id = 'xyz@example.com' AND b1.block_id='16' 
    SET r1.status='Skipped', r1.enddate=20141225
    WITH u, b2, g
    CALL apoc.do.when(
      b2.fork = 'y',
      "MERGE (u)-[:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2     {fork:'fail'})",
      "MERGE (u)-[:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2)",
      {u: u, b2: b2}) YIELD value
    WITH u, g
    MATCH (u)-[:TIME]->(h:Time)<-[:TIME]-(g)
    SET h.after = 0
    SET h.before = h.before + 1
    

    【讨论】:

      【解决方案4】:

      虽然这个答案对我有帮助,但我发现语法很难理解。所以这就是我写自己的答案的原因。在这里,我读取了一个 tsv 文件并生成了多种类型的边。

      LOAD CSV WITH HEADERS FROM 'file:///data.tsv' AS r FIELDTERMINATOR '\t'
      WITH r.movie_id as movie_id, r.person_id as person_id, r.category as category
      MATCH (p:Person {person_id:person_id})
      MATCH (m:Movie {movie_id:movie_id})
      FOREACH (_ IN CASE WHEN category='actress' THEN [1] ELSE [] END |
        MERGE (p)-[:ACTRESS {}]->(m)
      )
      FOREACH (_ IN CASE WHEN category='director' THEN [1] ELSE [] END |
        MERGE (p)-[:DIRECTOR {}]->(m)
      )    
      FOREACH (_ IN CASE WHEN category='cinematographer' THEN [1] ELSE [] END |
        MERGE (p)-[:CINEMATOGRAPHER {}]->(m)
      )
      FOREACH (_ IN CASE WHEN category='actor' THEN [1] ELSE [] END |
        MERGE (p)-[:ACTOR {}]->(m)
      )
      

      这里_ 是一些变量,它根本不在任何地方使用,而是密码语法的必需品

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-14
        • 1970-01-01
        相关资源
        最近更新 更多