【问题标题】:Neo4j/Cypher optionally create a Node and relationship based on whether a JSON object is empty or notNeo4j/Cypher 可选择根据 JSON 对象是否为空来创建节点和关系
【发布时间】:2021-02-25 17:44:40
【问题描述】:

首先,我使用带有 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 输入作为带有namedownloadURL 属性的JSON 发送。自定义输入类型:

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

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

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

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 是否是最有效的方法是什么,如果是则什么都不做,而不是在 NOT IS NULL 时运行 CREATE 节点/关系语句:

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))",

这是一个成功创建 Post 的 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 的帖子。也许解决方案是只创建两个不同的查询?

【问题讨论】:

  • 谢谢。我正在尝试使用 FOREACH,它成功创建了 Post,但不是 ImageReference(关于原因没有错误)。如果您有机会达到顶峰,我将其添加到问题中。欣赏!

标签: neo4j graphql cypher apollo grandstack


【解决方案1】:

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

例如,您的最后一个 sn-p 可以这样完成:

...
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
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多