cancel
Showing results for 
Search instead for 
Did you mean: 

Join the community at Nodes 2022, our free virtual event on November 16 - 17.

Using unwind in a call with cypherdsl

paulB
Node Clone

I have a cypher query and want to catch related nodes for each node in the result.
So my working raw cypher query looks like :

MATCH p = (:lookingType)<-[:specifiedRelation]-()
WITH nodes(p) AS nodes, relationships(p) AS relations
CALL {
 WITH nodes
 UNWIND nodes AS n
 MATCH second_p=(n)-[second_relations:otherRelation]->(second_nodes)
 RETURN second_nodes, second_relations
}
RETURN nodes, relations, collect(second_nodes), collect(second_relations)

In my java project, I want to use cypherdsl for this.
But, I have a problem using a Unwind inside a call. That's what I try :

OngoingReading imports = Cypher.unwind(Functions.nodes(first_path)).as("n");
Statement completeStatement = Cypher.match(first_path)
   .call(second_path,
       imports)
   .returning(nodes, relations, second_nodes, second_relations)
   .build();

But call doesn't manage OngoingReading objects. Is there any turn around?
As it is a common use case in my project, using only one query to the database is important.
I fail with multiple other ways. Thank you for reading and for your help.

1 ACCEPTED SOLUTION

Hi @paulB that whould be something like that:

SymbolicName nodes = Cypher.name("nodes");
		SymbolicName relations = Cypher.name("relations");
		SymbolicName second_nodes = Cypher.name("second_nodes");
		SymbolicName second_relations = Cypher.name("second_relations");

		NamedPath first_path = Cypher.path("p")
			.definedBy(
				Cypher.node("lookingType").relationshipFrom(Cypher.anyNode(), "specifiedRelation")
			);
		NamedPath second_path = Cypher.path("second_p")
			.definedBy(
				Cypher.anyNode("n")
					.relationshipTo(Cypher.anyNode().named(second_nodes), "otherRelation")
					.named(second_relations)
			);

		Statement inner = Cypher.unwind(nodes).as("n").with("n")
				.match(second_path)
				.returning(second_nodes, second_relations)
				.build();

		Statement completeStatement =
			Cypher
				.match(first_path)
				.with(Functions.nodes(first_path).as(nodes), Functions.relationships(first_path).as(relations))
				.call(inner, nodes.as("nodes"))
				.returning(nodes, relations, Functions.collect(second_nodes), Functions.collect(second_relations))
			.build();

which gives you

MATCH p = (:lookingType)<-[:specifiedRelation]-()
WITH nodes(p) AS nodes, relationships(p) AS relations
CALL {
  WITH nodes
  WITH nodes AS nodes
  UNWIND nodes AS n
  WITH n
  MATCH second_p = (n)-[second_relations:otherRelation]->(second_nodes)
  RETURN second_nodes, second_relations
}
RETURN nodes, relations, collect(second_nodes), collect(second_relations)

the 2nd with is ugly and is caused by that Call {} inner creates empty with when using an unnamed import. · Issue #319 · neo4j-contrib/cypher-d..., which I will fix soon.

View solution in original post

3 REPLIES 3

Hi @paulB that whould be something like that:

SymbolicName nodes = Cypher.name("nodes");
		SymbolicName relations = Cypher.name("relations");
		SymbolicName second_nodes = Cypher.name("second_nodes");
		SymbolicName second_relations = Cypher.name("second_relations");

		NamedPath first_path = Cypher.path("p")
			.definedBy(
				Cypher.node("lookingType").relationshipFrom(Cypher.anyNode(), "specifiedRelation")
			);
		NamedPath second_path = Cypher.path("second_p")
			.definedBy(
				Cypher.anyNode("n")
					.relationshipTo(Cypher.anyNode().named(second_nodes), "otherRelation")
					.named(second_relations)
			);

		Statement inner = Cypher.unwind(nodes).as("n").with("n")
				.match(second_path)
				.returning(second_nodes, second_relations)
				.build();

		Statement completeStatement =
			Cypher
				.match(first_path)
				.with(Functions.nodes(first_path).as(nodes), Functions.relationships(first_path).as(relations))
				.call(inner, nodes.as("nodes"))
				.returning(nodes, relations, Functions.collect(second_nodes), Functions.collect(second_relations))
			.build();

which gives you

MATCH p = (:lookingType)<-[:specifiedRelation]-()
WITH nodes(p) AS nodes, relationships(p) AS relations
CALL {
  WITH nodes
  WITH nodes AS nodes
  UNWIND nodes AS n
  WITH n
  MATCH second_p = (n)-[second_relations:otherRelation]->(second_nodes)
  RETURN second_nodes, second_relations
}
RETURN nodes, relations, collect(second_nodes), collect(second_relations)

the 2nd with is ugly and is caused by that Call {} inner creates empty with when using an unnamed import. · Issue #319 · neo4j-contrib/cypher-d..., which I will fix soon.

paulB
Node Clone

Hi @michael.simons1,

Thank you so much for your help.
I was doing something quite ugly with some CypherParser, thank god, you came in!
With this use case, I have a new point of view on the convenient SymbolicName.

Thank for your time and your work.

My pleasure! Your contribution helped me to discover the rendering bug (which was fixed, release will be done probably next week).