Dayel Ostraco
Dayel Ostraco

Reputation: 1913

SpringData Neo4j @Query does not populate @Relationship Nodes

The Spring Data for neo4j @Query annotation does not populate any child/parent Nodes marked by the @Relationship annotation.

When using the standard @CrudRepository or @PagingAndSortingRepository queries in a SpringData Repository class, the Child/Parent Nodes classes are returned fulled populated.

Repository Interface

@Repository("trackerRepository")
public interface TrackerRepository extends PagingAndSortingRepository<Tracker, String> {

    Tracker findByTrackerId(@NotNull String trackerId);
}

Node Class

public final class Tracker extends Node {

    @NotNull
    @JsonProperty("trackerId")
    private String trackerId;

    @NotNull
    @Relationship(type = "ASSIGNED_TO")
    @JsonProperty("asset")
    private Asset asset;

    @NotNull
    @Relationship(type = "ISSUED_BY")
    @JsonProperty("organization")
    private Organization organization;
}

When using the findByTrackerId method, the query generated by Spring using the method name/signature works perfectly and returns the fully populated Asset and Organization nodes.

However, when using the @Query annotation and not the Spring queries generated from the method signature, the @Relationship nodes are not returned with the query response.

Repository Interface

@Repository("trackerRepository")
public interface TrackerRepository extends PagingAndSortingRepository<Tracker, String> {

    @Query("MATCH (tracker:Tracker) WHERE (tracker.trackerId = $trackerId) RETURN tracker")
    Tracker findByTrackerId(@NotNull @Param("trackerId") String trackerId);
}

Is it possible to configure repository methods marked with @Query to join parent/child Nodes defined by the @Relationship annotation?

Upvotes: 0

Views: 770

Answers (2)

James Clover
James Clover

Reputation: 74

@false_memories has it right, but the WITH clause isn't necessary in this case. If you're just using variables from the match clause, you don't need a WITH. You need a WITH only if you're manipulating the variables in some way:

https://neo4j.com/docs/cypher-manual/current/clauses/with/#with-filter-on-aggregate-function-results

In addition, looks like your relationships are required from your @NotNull annotations, so you should drop the OPTIONAL

So a slightly better query is:

@Query("MATCH (tracker:Tracker {trackerId: $trackerId})
MATCH (tracker)-[r_issued_by:ISSUED_BY]->(organization:Organization)
MATCH (tracker)-[r_assigned_to:ASSIGNED_TO]->(asset:Asset)
RETURN tracker,
  COLLECT(r_issued_by), COLLECT(organization) AS organization,
  COLLECT(r_assigned_to), COLLECT(asset) AS asset")

I like to match the as clause to my actual relationship names because it makes it appear a little cleaner when looking at raw results.

Upvotes: 0

roguequery
roguequery

Reputation: 974

When writing a custom query with @Query you need to specify exactly what you're bringing back:

@Relationship(type = "ASSIGNED_TO")
@JsonProperty("asset")
private Asset asset;

@NotNull
@Relationship(type = "ISSUED_BY")
@JsonProperty("organization")
private Organization organization;

Alternatively (I'm assuming this is SDN 6 with Spring Data as opposed to SDN 5 and OGM?) you can just drop the custom query and use the out-of-the-box SPEL of findByTrackerId and the repository methods will create a automagical Cypher query that gets seamlessly serialized by the @Repository methods.

In general custom @Query is useful when needing to write more efficient queries then those offered by the SDN sugars.

But to answer your question more directly this should work:

@Query("MATCH (tracker:Tracker {trackerId: $trackerId})
WITH tracker
OPTIONAL MATCH (tracker)-[r_issued_by:ISSUED_BY]->(organization:Organization)
WITH tracker, COLLECT(r_issued_by) AS organization_rels, COLLECT(DISTINCT organization) AS organizations 
OPTIONAL MATCH (tracker)-[r_assigned_to:ASSIGNED_TO]->(asset:Asset)
RETURN tracker, organization_rels, organizations, COLLECT(r_assigned_to) AS asset_rels, COLLECT(DISTINCT asset) AS assets;")

Looking at your annotations it looks like both ISSUED_BY and ASSIGNED_TO are outgoing relationships from :Tracker?

the collects are because of this:

https://community.neo4j.com/t/sdn-rx-dynamic-relationships-not-being-populated-with-custom-query/24456

Upvotes: 3

Related Questions