使用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
相关产品推荐
相关产品推荐

