cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

How to detech which Cypher statement goes wrong

Greetings,

Recently I'm looking into the docs of Cypher and write a simple Cypher query in Golang,
I've tried to use multiple statements inside a single transaction.

but If I input a invalid id of children or parent and make the middle MATCH statements failed on purpose, the transaction will not return anything for me (result.Next() is nil). So the whole function will only return No data returned

in this way I cannot know which statement goes wrong. Any suggestions?

Thanks a lot!

_, err = session.WriteTransaction(func(transaction neo4j.Transaction) (interface{}, error) {
		result, err := transaction.Run(
			`CREATE (currentNode:Location $props)
			WITH currentNode
			OPTIONAL MATCH (children:Location) WHERE children.id IN $children
			MERGE (currentNode)-[:contains]->(children)
			WITH currentNode, children
			OPTIONAL MATCH (parent:Location{id:currentNode.parent})
			MERGE (parent) -[:contains]-> (currentNode)
			WITH currentNode, parent, children
			OPTIONAL MATCH path=(currentNode)-[contains*]-> (currentNode)
			WHERE length(path) > 0
			RETURN {cycle: length(path), children: children.id, parent: parent.id}`, map[string]interface{}{"props": input, "children": child})
		if err != nil {
			return nil, err
		}

		if result.Next() {

			returnedMap := result.Record().GetByIndex(0).(map[string]interface{})
			cycle := returnedMap["cycle"].(int64)
			parent := returnedMap["parent"].(string)
			children := returnedMap["parent"].(string)
			if parent == ""  {
				errMsg := "Cannot find the given parent of the location"
				return nil, errors.New(errMsg)
			} else if children == "" {
				errMsg := "Cannot find the given children of the location"
				return nil, errors.New(errMsg)
			} else if cycle > 0 {
				errMsg := " Cycle Detected"
				return nil, errors.New(errMsg)
			}

		} else {
			return nil, errors.New("No data returned")
		}

		if result.Err() != nil {
			return nil, result.Err()
		}
		return nil, nil

	})
1 ACCEPTED SOLUTION

HI John,

What you want to load?
Assuming it is:
(Location)-[:contains]->(Location)

First my comments on your statement:
CREATE (currentNode:Location $props)
WITH currentNode
OPTIONAL MATCH (children:Location) WHERE children.id IN $children
MERGE (currentNode)-[:contains]->(children)

The MERGE is never optional so if you want to merge an 'optional child' that will not work. Also you forgot the colon for the relationship type by the path= section

I think you should go the MERGE route all the way, make sure that you have an UNIQUE CONSTRAINT on Location.id

My cypher would be like this to create a structure:
WITH $props as data
MERGE (currentNode:Location { id: data.id })
ON CREATE SET currentNode += data
FOREACH (y in $children |
MERGE (child:Location { id: y })
MERGE (currentNode)-[:contains]->(child)
)
MERGE (parentNode:Location { id: data.parent} )
MERGE (parentNode)-[:contains]->(currentNode)

Than in a second call i would check fo cyclic paths but you can add the also the MATCH line below the merge above:
WITH $props as data
MATCH path = (currentNode:Location { id: data.id})-[:contains0..*]->(currentNode)
WHERE length(path) > 0
RETURN currentNode{ cycle: length(path), children : [ (currentNode)-[:contains]->(child:Location) | child.id ], parent: parentNode.id }

A note about the '0' in the variable path length query: When the path length = 0 you only have the currentNode back. This is faster than using OPTIONAL MATCH.

To give a final answer on how to detect if a cypher statement goes wrong, is to test it first in the neo4j browser and use explain/profile before your statement. You can use here :param to create query parameters.

I hope this will help you

View solution in original post

1 REPLY 1

HI John,

What you want to load?
Assuming it is:
(Location)-[:contains]->(Location)

First my comments on your statement:
CREATE (currentNode:Location $props)
WITH currentNode
OPTIONAL MATCH (children:Location) WHERE children.id IN $children
MERGE (currentNode)-[:contains]->(children)

The MERGE is never optional so if you want to merge an 'optional child' that will not work. Also you forgot the colon for the relationship type by the path= section

I think you should go the MERGE route all the way, make sure that you have an UNIQUE CONSTRAINT on Location.id

My cypher would be like this to create a structure:
WITH $props as data
MERGE (currentNode:Location { id: data.id })
ON CREATE SET currentNode += data
FOREACH (y in $children |
MERGE (child:Location { id: y })
MERGE (currentNode)-[:contains]->(child)
)
MERGE (parentNode:Location { id: data.parent} )
MERGE (parentNode)-[:contains]->(currentNode)

Than in a second call i would check fo cyclic paths but you can add the also the MATCH line below the merge above:
WITH $props as data
MATCH path = (currentNode:Location { id: data.id})-[:contains0..*]->(currentNode)
WHERE length(path) > 0
RETURN currentNode{ cycle: length(path), children : [ (currentNode)-[:contains]->(child:Location) | child.id ], parent: parentNode.id }

A note about the '0' in the variable path length query: When the path length = 0 you only have the currentNode back. This is faster than using OPTIONAL MATCH.

To give a final answer on how to detect if a cypher statement goes wrong, is to test it first in the neo4j browser and use explain/profile before your statement. You can use here :param to create query parameters.

I hope this will help you