Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
02-21-2022 07:29 AM
I have created a node class called MyNode
and an edge class called MyEdge
as follows:
@Node
public class MyNode {
@Id
String id;
String name;
String type;
@Relationship(type = "CONTAINS")
Set<MyEdge> outgoingEdges = new HashSet<>();
public MyNode() {
}
public MyNode(String id, String name, String type) {
this.id = id;
this.name = name;
this.type = type;
}
// Getters and setters...
and
@RelationshipProperties
public class MyEdge {
@Id
String id;
String idNodeFrom;
String idNodeTo;
@TargetNode
MyNode targetNode;
public MyEdge(String idNodeFrom, String idNodeTo, MyNode targetNode) {
this.id = idNodeFrom + " -> " + idNodeTo;
this.idNodeFrom = idNodeFrom;
this.idNodeTo = idNodeTo;
this.targetNode = targetNode;
}
// Getters and setters
}
Note that on MyEdge
I have annotated the field id with @Id
instead of @RelationshipId
as being indicated here. And the reason for this is because somehow IntelliJ can't find the @RelationshipId
annotation although I have the following in my pom.xml
file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
</dependency>
So my first question is how can I fix that? And my second and most important one is:
Why does the findAll
method of the MyEdge
repository (as seen below) always return an empty list?
public interface MyEdgeNeo4jRepository extends Neo4jRepository<MyEdge, String> {
@Query("MATCH ()-[e]->() RETURN e")
Collection<MyEdge> customFindAllEdges();
}
I have connected to the database through my browser and have verified that the nodes and the relationships are modeled as they should be. But still, when I call
Collection<MyEdge> ret = myEdgeNeo4jRepository.findAll();
for (MyEdge myEdge: ret) {
System.out.println(myEdge);
}
nothing gets printed.
Another thing I have tried is to use a class-based projection, namely the following class
public class MyEdge2 {
String idNodeTo;
String idNodeFrom;
public MyEdge2() {
}
public MyEdge2(String idNodeTo, String idNodeFrom) {
this.idNodeTo = idNodeTo;
this.idNodeFrom = idNodeFrom;
}
// Getters and setters
}
and then try
@Query("MATCH ()-[e]->() RETURN e")
Collection<MyEdge2> customFindAllEdges();
but this approach throws the following exception
org.springframework.data.neo4j.core.mapping.NoRootNodeMappingException: Could not find mappable nodes or relationships inside Record<{e: relationship<5630>}> for org.springframework.data.neo4j.core.mapping.DefaultNeo4jPersistentEntity@504aa259
Any help would be appreciated! Thanks very much in advance!
Solved! Go to Solution.
02-21-2022 08:29 AM
First step: Change the repository to be of type <MyNode, String>
If you really want to use a custom cypher statement:
@Query("MATCH (n1:MyNode)-[r]->(n2:MyNode) RETURN n1, collect(r), collect(n2)"
MyNode customFindAllEdges(); // of course the name does not really make a lot of sense now
And then operate on the returned and populated object:
MyNode myNode = repository.customFindAllEdges();
for (MyEdge edge : myNode.outgoingEdges) {
}
If there are multiple MyNode
s that could get returned, use a List<MyNode>
instead of just MyNode
.
02-21-2022 08:03 AM
You cannot query directly for relationships. (ok, you showed that it is technical possible with a custom query )
Spring Data Neo4j does not support relationships as first class entities (since version 6.0). If you want to query for MyEdge
, you would have to load MyNode
(e.g. via a ... extends Neo4jRepository<MyNode, String>
).
Just a side note: The identifier of a RelationshipProperties
class should always be of type Long
and annotated with @GeneratedValue
. The @RelationshipId
annotation is (for now) just a shortcut for those annotations. One reason why you have not seen it in your dependencies might be that it is only available from 6.2.x onward.
02-21-2022 08:16 AM
Can I try a custom query like this?
@Query("MATCH (n1)-[]->(n2) RETURN n1, n2"
ReturnType??? customFindAllEdges();
But then what would the return type be?
02-21-2022 08:29 AM
First step: Change the repository to be of type <MyNode, String>
If you really want to use a custom cypher statement:
@Query("MATCH (n1:MyNode)-[r]->(n2:MyNode) RETURN n1, collect(r), collect(n2)"
MyNode customFindAllEdges(); // of course the name does not really make a lot of sense now
And then operate on the returned and populated object:
MyNode myNode = repository.customFindAllEdges();
for (MyEdge edge : myNode.outgoingEdges) {
}
If there are multiple MyNode
s that could get returned, use a List<MyNode>
instead of just MyNode
.
02-22-2022 03:53 AM
I tried that and it seems to work! So, thank you very much for that. There is still a weird thing going on though.
If i run the following piece of code
Set<MyNode> nodes = new HashSet<>();
Set<MyEdge> edges = new HashSet<>();
// The method you suggested above
Collection<MyNode> ret = myNodeNeo4jRepository.customFindAllEdges();
for (MyNode myNode: ret) {
nodes.add(myNode);
for (MyEdge myEdge: myNode.getOutgoingEdges()) {
edges.add(myEdge);
nodes.add(myEdge.getTargetNode());
System.out.println(myEdge.getIdNodeFrom() + " -> " + myEdge.getIdNodeTo());
}
}
System.out.println("edges count");
System.out.println(edges.size());
System.out.println("nodes count");
System.out.println(nodes.size());
it prints edge count 2781
whereas if I connect to the db form my browser and run the following query
MATCH ()-[e]->() RETURN count(e)
it returns 2852
.
(The nodes count
is correct)
Any idea why that might be happening?
Thanks again
02-22-2022 04:00 AM
I would assume that there are probably 2852-2781 = 71
relationships not having the CONTAINS
type.
02-22-2022 04:02 AM
Not really. There are only relationships of the CONTAINS
type.
This query MATCH ()-[e:CONTAINS]->() RETURN count(e)
returns 2852
also
02-22-2022 04:06 AM
What returns MATCH (:MyNode)-[e:CONTAINS]->(:MyNode) RETURN count(e)
?
02-22-2022 04:07 AM
It also returns 2852
02-22-2022 05:05 AM
Out of curiosity: What is the outcome if you use repository.findAll()
instead of the custom query?
It might take a little bit more time because it will load everything reachable from MyNode
.
Another idea based on this line:
Set<MyEdge> edges = new HashSet<>();
You do not define an equals
in MyEdge
that might produce true
for two (physical) different edges?
02-22-2022 06:01 AM
Yeah I looked into it a bit and it seems that there were some multiple edges between the same nodes and thus the equals
method I had overrode would not let them be counted in the set. Thanks a lot for that!
One last thing I wanted to ask. I want to get the sub graph that starts from a given node and the cypher query I have written for that is
MATCH p = (n1 {id: $nodeId})-[*]->(n2) RETURN p
But I'm having trouble with the return type. If I write it like this
@Query("MATCH p = (n1 {id: \"random_id\"})-[*]->(n2) RETURN p")
Collection<MyNode> customFindSubGraph();
and then use it like this
Collection<MyNode> ret = myNodeNeo4jRepository.customFindSubGraph();
for (MyNode myNode: ret) {
for (MyEdge myEdge: myNode.getOutgoingEdges()) {
System.out.println(myEdge.getIdNodeFrom() + " -> " + myEdge.getTargetNode());
}
}
then for the target node, the set of its outgoing edges is always empty. For example it prints
id_1-> MyNode{id='id_2', name='random_name_2', type='type_1', outgoingEdges=[]}
id_5-> MyNode{id='id_7', name='random_name_7', type='type_2', outgoingEdges=[]}
What I would expect is that I would get the following nodes in the path inside the outgoingEdges list, but it's always empty. What am I doing wrong?
Again, thanks a lot!
All the sessions of the conference are now available online