You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用apoc.do.when时变量rn未定义的Neo4j查询报错排查

问题解决:apoc.do.when中变量rn未定义报错

问题背景

在FastAPI请求中执行Neo4j查询,通过apoc.do.when根据Resource_Type节点的name字段做分支处理,执行时提示变量rn未定义,但该变量已在apoc.do.when的参数中传入。

相关代码与报错

FastAPI代码

@app.post("/filter/create", status_code=201)
def create_filter(request: FilterCreateRequest):
    filter_id = str(uuid.uuid4())
    try:
        with get_driver() as driver:
            with driver.session() as session:
             
                result = session.run(f"""
                    MATCH (rt:Resource_Type {{name: '{request.resource_type_name}'}})
                    CREATE (filter:Filter {{id: '{filter_id}', name: '{request.name}'}})
                    WITH rt, filter
                    UNWIND {request.tag_list} AS tag_name
                    MATCH (tag:Tag {{name: tag_name}})
                    MERGE (filter)-[:{config['Filter']['Tag']}]->(tag)
                    WITH rt, filter, {request.tag_list} AS liste, '{request.resource_name}' AS rn, '{request.resource_type_name}' AS rtn
                    
                    WITH rt,filter, liste, rn, rtn
                    CALL apoc.do.when(
                    rt.name = 'User',
                    'MATCH (user:User) ' +
                    'WHERE ALL(tag IN liste WHERE (user)-[:{config['User']['Tag']}]->(:Tag {{name: tag}})) ' +
                    'WITH user, filter ' +
                    'CREATE (filter)-[:{config['Filter']['User']}]->(user) ' +
                    'WITH filter ' +
                    'MATCH (group:Group {{name: rn}}) ' +
                    'CREATE (group)-[:{config['Group']['Filter']}]->(filter) ' +
                    'RETURN count(filter) AS created',
                    'MATCH (res:Resource)-[:{config['Resource']['Resource_Type']}]->(:Resource_Type {{name: rtn}}) ' +
                    'WHERE ALL(tag IN liste WHERE (res)-[:{config['Resource']['Tag']}]->(:Tag {{name: tag}})) ' +
                    'WITH res, filter ' +
                    'CREATE (filter)-[:{config['Filter']['Resource']}]->(res) ' +
                    'WITH filter ' +
                    'MATCH (role:Role {{name: rn}}) ' +
                    'CREATE (role)-[:{config['Role']['Filter']}]->(filter) ' +
                    'RETURN count(filter) AS created',
                    {{rt: rt, filter: filter, liste:liste, rn: rn, rtn: rtn}}
                    )
                    YIELD value
                    RETURN value.created
                """)


                created_count = result.single()
                if created_count > 0:
                    return {"message": "Filter created and linked successfully", "filter_id": filter_id}
                else:
                    return {"message": "Resource_Type not found or invalid resource_id"}

    except Exception as e:
        raise HTTPException(status_code=400, detail=f"An error occurred: {str(e)}")

报错信息

'An error occurred: {code: Neo.ClientError.Procedure.ProcedureCallFailed} {message: Failed to invoke procedure `apoc.do.when`: Caused by: org.neo4j.exceptions.SyntaxException: Variable `rn` not defined (line 1, column 328 (offset: 327))\n" WITH  $`filter` as `filter` ,  $`rt` as `rt` ,  $`liste` as `liste` ,  $`rn` as `rn` ,  $`rtn` as `rtn` MATCH (res:Resource)-[:IS_A]->(:Resource_Type {name: rtn}) WHERE ALL(tag IN liste WHERE (res)-[:HAS_TAG]->(:Tag {name: tag})) WITH res, filter CREATE (filter)-[:FILTERS_RESOURCE]->(res) WITH filter MATCH (role:Role {name: rn}) CREATE (role)-[:USES_FILTER]->(filter) RETURN count(filter) AS created"\n                                                                                                                                                                                                                                                                                                                                        ^}'

直接执行的Cypher语句

MATCH (rt:Resource_Type {name: 'Server'})
CREATE (filtr: Filter {id: '29a31db0-6149-4f79-ad0b-16f4efe66a71', name: 'AccessFilter'})                    
WITH rt, filtr                    
UNWIND ['boosting', 'data'] AS tag_name
MATCH (tag: Tag {name: tag_name})
MERGE (filtr)-[:INCLUDE_TAG]->(tag)
WITH rt, filtr,'Administrator' AS rn, ['boosting', 'data'] AS liste,  'Server' AS rtn

WITH rt,filtr, rn,liste, rtn
CALL apoc.do.when(
     rt.name = 'User',
     'MATCH (user: User) 
     WHERE ALL(tag IN liste WHERE (user)-[:HAS_TAG]->(:Tag {name: tag})) 
     WITH user, filtr, rn 
     CREATE (filtr)-[:FILTERS_USER]->(user) 
     WITH filtr , rn
     MATCH (group: Group {name: rn})                
     CREATE (group)-[:USES_FILTER]->(filtr)                   
     RETURN count(filtr) AS created ',

     'MATCH (res:Resource)-[:IS_A]->(:Resource_Type {name: rtn}) 
     WHERE ALL(tag IN liste WHERE (res)-[:HAS_TAG]->(:Tag {name: tag})) 
     WITH res, filtr, rn 
     CREATE (filtr)-[:FILTERS_RESOURCE]->(res) 
     WITH filtr, rn                     
     MATCH (role: Role {name: rn}) 
     CREATE (role)-[:USES_FILTER]->(filtr) 
     RETURN count(filtr) AS created ',
     {rt: rt, filtr: filtr, liste:liste, rn: rn, rtn: rtn}                    )
YIELD value                    
RETURN value.created 

问题原因

报错核心是分支Cypher中的WITH语句丢失了rn变量:

  • User分支中,执行CREATE后用WITH filter传递变量,但未携带rn,导致后续MATCH (group:Group {name: rn})找不到变量。
  • Resource分支中,同样在CREATE后用WITH filter未携带rn,后续MATCH (role:Role {name: rn})触发未定义报错。
  • 额外问题:原代码用字符串拼接生成Cypher,存在注入风险,且转义逻辑易出错。

解决方案

1. 修复分支Cypher的WITH语句

修改两个分支的Cypher,在WITH语句中带上后续需要的rn变量:

user_branch = """
MATCH (user:User) 
WHERE ALL(tag IN liste WHERE (user)-[:{user_tag}]->(:Tag {{name: tag}})) 
WITH user, filter, rn 
CREATE (filter)-[:{filter_user}]->(user) 
WITH filter, rn
MATCH (group:Group {{name: rn}}) 
CREATE (group)-[:{group_filter}]->(filter) 
RETURN count(filter) AS created
""".format(
    user_tag=config['User']['Tag'],
    filter_user=config['Filter']['User'],
    group_filter=config['Group']['Filter']
)

resource_branch = """
MATCH (res:Resource)-[:{res_type}]->(:Resource_Type {{name: rtn}}) 
WHERE ALL(tag IN liste WHERE (res)-[:{res_tag}]->(:Tag {{name: tag}})) 
WITH res, filter, rn 
CREATE (filter)-[:{filter_res}]->(res) 
WITH filter, rn
MATCH (role:Role {{name: rn}}) 
CREATE (role)-[:{role_filter}]->(filter) 
RETURN count(filter) AS created
""".format(
    res_type=config['Resource']['Resource_Type'],
    res_tag=config['Resource']['Tag'],
    filter_res=config['Filter']['Resource'],
    role_filter=config['Role']['Filter']
)

2. 使用参数化查询替代字符串拼接

改用Neo4j参数化查询,避免注入风险,提升代码可读性:

result = session.run("""
    MATCH (rt:Resource_Type {name: $resource_type_name})
    CREATE (filter:Filter {id: $filter_id, name: $filter_name})
    WITH rt, filter
    UNWIND $tag_list AS tag_name
    MATCH (tag:Tag {name: tag_name})
    MERGE (filter)-[:{filter_tag}]->(tag)
    WITH rt, filter, $tag_list AS liste, $resource_name AS rn, $resource_type_name AS rtn
    
    CALL apoc.do.when(
        rt.name = 'User',
        $user_branch,
        $resource_branch,
        {rt: rt, filter: filter, liste: liste, rn: rn, rtn: rtn}
    )
    YIELD value
    RETURN value.created
""".format(filter_tag=config['Filter']['Tag']),
    resource_type_name=request.resource_type_name,
    filter_id=filter_id,
    filter_name=request.name,
    tag_list=request.tag_list,
    resource_name=request.resource_name,
    user_branch=user_branch,
    resource_branch=resource_branch
)

3. 验证逻辑

直接执行的Cypher已正确在WITH语句中携带rn,因此可以正常运行,这也验证了变量传递逻辑的正确性。


内容的提问来源于stack exchange,提问作者Chrysos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 00:08:11