0

首先,我使用带有 Flutter 的 GRANDstack 作为我的前端。不是超级相关,但对于上下文。我有一个 CreatePost 突变:

mutation CreatePost(\$body: String!, \$userId: ID!, \$imageReference: CreateImageReference!, \$mentions: [String!]) {
  CreatePost(body: \$body, userId: \$userId, imageReference: \$imageReference, mentions: \$mentions) {
    id,
    body,
    createdAt {
      formatted
    },
    updatedAt {
      formatted
    },
    user {
      username
    },
    imageReference {
      downloadURL
    }
  }
}

这成功地将我的输入作为带有和属性CreateImageReference的 JSON发送。自定义输入类型:namedownloadURL

input CreateImageReference {
    name: String!
    downloadURL: String!
}

在我的模式文件中很简单,并且被 apollo/graphql 接受就好了。我正在记录“graphqlResponse”以监控所有内容,到目前为止似乎没有问题。

我正在尝试根据参数是否为空来“选择性地创建”该ImageReference节点以及与该节点的关系。我的自定义突变与密码查询没有添加逻辑:Post$imageReferenceImageReference

CreatePost(body: String!, userId: ID!, imageReference: CreateImageReference!, mentions: [String!]): Post
    @cypher(
      statement: """
        MATCH (u:User {id: $userId})-[:MEMBER_OF]->(g:Group)
        OPTIONAL MATCH (g)-[rel:NEWEST_POST]->(prevNewest:Post)
        CREATE (u)-[:WROTE]->(p:Post {id: apoc.create.uuid(), body: $body, createdAt: datetime(), updatedAt: datetime()})<-[:NEWEST_POST]-(g)
        MERGE (u)-[hp:HAS_PARTICIPATED]->(g)
        ON MATCH SET hp.updatedAt = p.createdAt
        ON CREATE SET hp.createdAt = p.createdAt, hp.updatedAt = p.createdAt
        FOREACH(i in CASE WHEN NOT rel IS NULL THEN [1] ELSE [] END |
        DELETE rel CREATE (p)-[:NEXT_POST]->(prevNewest))
        WITH p
        OPTIONAL MATCH (allMentionedUsers:User)
        WHERE allMentionedUsers.id in $mentions
        UNWIND allMentionedUsers as mentionedUser
        MERGE (p)-[:MENTIONS]->(mentionedUser)
        // Add CREATE ImageReference and
        // Add CREATE relationship (HAS_ATTACHMENT) between ImageReference and Post here
        RETURN p
    """)

检查变量 $imageReference 是否是最有效的方法是IS NULL什么,如果是,则什么都不做,而不是在以下情况下运行 CREATE 节点/关系语句NOT IS NULL

CREATE (i:ImageReference {id: apoc.create.uuid(), name: $imageReference['name'], downloadURL: $imageReference['downloadURL']}
WITH i
CREATE (p)-[:HAS_ATTACHMENT]-(i)

这是 CASE 的尝试:

CASE $imageReference
WHEN null []
ELSE CREATE (i:ImageReference {
    id: apoc.create.uuid(), 
    name: $imageReference['name'], 
    downloadURL: $imageReference['downloadURL'],
    createdAt: datetime(),
    updatedAt: datetime(),
    deletedAt: null
})
CREATE (p)-[:HAS_ATTACHMENT]->(i)
WITH i END

那是扔一个"Neo4jError: Failed to invoke procedure apoc.cypher.doIt : Caused by: org.neo4j.exceptions.SyntaxException: Invalid input 'S': expected 'l/L' (line 10, column 3 (offset: 678))",

这是成功创建帖子的 FOREACH 尝试,但没有错误的 ImageReference 来说明原因:

FOREACH (i in CASE WHEN NOT $imageReference IS NULL THEN [1] ELSE [] END |
    CREATE (ir:ImageReference {
        id: apoc.create.uuid(), 
        name: $imageReference['name'], 
        downloadURL: $imageReference['downloadURL'],
        createdAt: datetime(),
        updatedAt: datetime(),
        deletedAt: null
    })
    CREATE (p)-[:HAS_ATTACHMENT]->(ir))

如果我执行这部分:

CREATE (ir:ImageReference {
    id: apoc.create.uuid(), 
    name: $imageReference['name'], 
    downloadURL: $imageReference['downloadURL'],
    createdAt: datetime(),
    updatedAt: datetime(),
    deletedAt: null
})
CREATE (p)-[:HAS_ATTACHMENT]->(ir))

如果没有 CASE 或 FOREACH,它会按预期成功创建节点和关系,这很好,直到我想创建没有 ImageReference 的帖子。也许解决方案只是创建两个不同的查询?

4

1 回答 1

0

您可以使用 APOC 过程apoc.do.when执行可以写入数据库的 if-then-else 处理(apoc.when可用于只读处理)。

例如,您的最后一个片段可以这样完成:

...
CALL apoc.do.when(
  $imageReference IS NOT NULL,
  ' CREATE (ir:ImageReference {
      id: apoc.create.uuid(), 
      name: ref.name, 
      downloadURL: ref.downloadURL,
      createdAt: datetime(),
      updatedAt: datetime()
    })
    CREATE (p)-[:HAS_ATTACHMENT]->(ir)
    RETURN ir',
  '',
  {ref: $imageReference, p: p}
) YIELD value
WITH p, value.ir AS ir
...
于 2020-11-13T20:38:20.027 回答