Dynamic query

Hi,

I would need to generate dynamic queries, to add some filters on conditions.
Let say that my app handle Books and Authors. Books concerns one or more Theme.
User can filter by Theme.
So a query could be :

MATCH (b:Book)-[w:WRITEN]-(a:Author) MATCH (b:Book)-[c:CONCERNS]-(t:Theme {id : '1234'}) return b, w, a, c, t

Sometimes book's theme is unknown so a Book is not associated with any Theme.
If user doesn't pick any filter, query would be :

MATCH (b:Book)-[w:WRITEN]-(a:Author) OPTIONAL MATCH (b:Book)-[c:CONCERNS]-(t:Theme) return b, w, a, c, t

In this case I can not go with @Query because of the optional filter and MATCH.
From what I saw, queryDSL is not supported (yet?)

Is there any way to generate query with conditions, like we can do with Criteria for relational DB?

Many thx

A gloriously simple solution is to call a different @Repository method for each case, depending whether your themeId is null.

Otherwise, you could write your own function. See some docs on this here: https://docs.spring.io/spring-data/neo4j/docs/5.0.0.RELEASE/reference/html/#repositories.single-repository-behavior.

For whatever it is worth a year later, but might help others, there is a way to do dynamic cypher with the help of the APOC library.
Consider this query:

@QUERY("CALL apoc.cypher.doIt({filterQuery}, {id: {id}}) " +
"YIELD value AS v_res RETURN x,y,z")
myQuery(String filterQuery, Long id);

So filterQuery is dynamically built in the code and you can also pass into it parameters like {id} in this example.

The other options it to move away from Spring Data and use the Java driver directly or use a custom Neo4j plugin.

Sorry I am facing one issue with this approach,

    @Query("match (:Customer{username:$0})-[*1..2]->(i:Insight{id: $1}) " +
            "match (i)-[:OF_QUERY]->(query:Query{isLatest: true}) " +
            "CALL apoc.cypher.doIt("match (i:Insight) return i",null) YIELD value " +
            "return value")
    fun fetchInsightData(username: String, insightId: String): Flux<Insight>

spring boot refuses to cast the query to Flux even though I HAVE TESTED it in neo4j console and it works fine.

I found the solution for it , simply name the returned results from the inner query as so:

    @Query("match (:Customer{username:$0})-[*1..2]->(i:Insight{id: $1}) " +
            "match (i)-[:OF_QUERY]->(query:Query{isLatest: true}) " +
            "CALL apoc.cypher.doIt("match (i:Insight) return i as GG",null) YIELD value " +
            "return value.GG")
    fun fetchInsightData(username: String, insightId: String): Flux<Insight>

One small comment, you're using:

apoc.cypher.doIt

which uses a write transaction. It is not needed here and you can use a read transaction for better performance:

apoc.cypher.run