Search code examples
neo4jspring-datacypherspring-data-neo4jspring-data-neo4j-4

Neo4j Session.query() - How to map query response to Custom Java Object


I have a Node Entity:

@NodeEntity(label = CollectionNames.CONSUMER)
public class Consumer extends AbstractNode{

    //Properties, removed just for simplicity

    @Relationship(type = RelationshipNames.HAS_CONTACT, direction = Relationship.OUTGOING)
    private Set<HasContact> contactList;

//Constructor & Getters, Setters
}

For Storing custom query results:

@QueryResult
public class CustomQueryResult {

    private AbstractNode node;
    private List<? extends AbstractRelationship> relationships;

    public CustomQueryResult(AbstractNode node, List<? extends AbstractRelationship> relationships){
        this.node = node;
        this.relationships = relationships;
    }

//Default Constructor, Getters & Setters
}

Repository Implementation

String query = String.format(
                "MATCH (startNode:Consumer {mobileNumber : {mob}})-[rel:%s *%d..%d]->(endNode:%s) RETURN startNode as node, rel as relationships",
                relationshipName, 0, depth, endNode);
        Map<String, Object> params = new HashMap<>();
        params.put("mob", mobileNo);
        CustomQueryResult consumer =  session.queryForObject(CustomQueryResult.class, query, params);

Although given Query load required data, but unfortunately its unable to map it to given Object(CustomQueryResult). But in case if I map it to Consumer then it show given error:

java.lang.RuntimeException: Result not of expected size. Expected 1 row but found 6

While this same query is working fine, if I use Spring Data Neo4j Repository like

@Query("MATCH (startNode:Consumer {mobileNumber : {0}})-[rel:HAS_CONTACT *..1]->(endNode:Consumer) RETURN startNode as node, rel as relationships")
    CustomQueryResult findByMobileNumberAndRelationship(String mobileNo);

So how can I map given query result into Consumer or CustomQueryResult object directly?

Or is that possible to do the same thing using Spring Data Neo4j Repository with dynamic Relationship names and depth like:

@Query("MATCH (startNode:Consumer {mobileNumber : {0}})-[rel:{1} *..{2}]->(endNode:Consumer) RETURN startNode as node, rel as relationships")
    CustomQueryResult findByMobileNumberAndRelationship(String mobileNo, String relationshipName, @Depth int depth);

Although I am sure that above code is not working.


Solution

  • Your query returns multiple rows

    MATCH (startNode:Consumer {mobileNumber : {0}})-[rel:HAS_CONTACT *..1]->(endNode:Consumer) 
    RETURN startNode as node, rel as relationships
    

    where node is repeated for each rel. The repository infrastructure is able to handle that, but queryForObject is not - it expects single row.

    It should work if you modify your query in following way so it returns only 1 row:

    MATCH (startNode:Consumer {mobileNumber : {0}})-[rel:HAS_CONTACT *..1]->(endNode:Consumer) 
    RETURN startNode as node, COLLECT(rel) as relationships