Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

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

Yes, the ISSUED_BY and ASSIGNED_TO relationships are outgoing and your provided query worked! Our intent wasn't to avoid the powerful SDN sugars, but to be able to avoid wonky method names for more complex Relationship-based filters: `` Tracker findByUidAndOrganization_OrganizationIdIn(@NotNull @Param("uid") String uid, @NotNull String[] organizationIds); `` However, the value of the SDN sugars vastly outweigh the perceived value of the method name syntax. There are far worse things than method names with underscores. :-) Green checkmark and +1 for the MASSIVE assist! – Dayel Ostraco Mar 25, 2021 at 11:44

@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.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.