querying and converting a neo4j query result to multi dimensional #QueryResult object - java

I have a #QueryResult interface, which itself declares a getter method that returns a list of objects of the same type. I wonder if there is a way to convert a neo4j query result to a proxied object that implements this domain interface ?
Here is the interface of the domain I tried for testing, which did not work:
#QueryResult
public interface Test
{
#ResultColumn( "id" )
public String getId();
#ResultColumn( "name" )
public String getName();
#ResultColumn( "tests" );
java.util.Collection<Test> getTests();
}
I used neo4Template#query( String, Map) to convert the query below to a proxied object that implements the above interface
MATCH (n:Label {id:{id}) WITH n MATCH (n)-[:INCLUDES]->(s) with n, s, COLLECT ({id:s.id, name:s.name}) AS tests RETURN n.name as name, n.id as id, tests
However, I got this exception:
Expexted a column named toString to be in the result set.
at
org.springframework.data.neo4j.support.conversion.ResultColumnValueExtractor.extractFromAccessibleObject(ResultColumnValueExtractor.java:74)
at org.springframework.data.neo4j.support.conversion.ResultColumnValueExtractor.extractFromMethod(ResultColumnValueExtractor.java:56)
at org.springframework.data.neo4j.support.conversion.QueryResultProxy.invoke(QueryResultProxy.java:54)
at com.sun.proxy.$Proxy173.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2854)
at java.lang.StringBuilder.append(StringBuilder.java:128)
at org.neo4j.helpers.collection.IteratorUtil.single(IteratorUtil.java:338)
at org.neo4j.helpers.collection.IteratorUtil.singleOrNull(IteratorUtil.java:128)
at org.neo4j.helpers.collection.IteratorUtil.singleOrNull(IteratorUtil.java:286)
at org.springframework.data.neo4j.conversion.QueryResultBuilder.singleOrNull(QueryResultBuilder.java:71)
Does anyone know if this is possible to achieve using spring data neo4j? Thanks for your help

Related

Spring data neo4j: How to append dynamic #Query?

How to generate dynamic value of #Query when have complex queries in Neo4jRepository ? Like:
#Repository
public interface StockRepository extends Neo4jRepository<StockNode,Long> {
#Query("match (n:stock) where n.name={aShareShortName} return n")
List<StockNode> getStockNodeByAShareShortName(#Param("aShareShortName") String aShareShortName);
#Query("match (n:stock) where n.{indexName}={indexContent} return n")
List<StockNode> getStockNodeByQueryProperty(#Param("indexName")String indexName,String indexContent);
}
The first method getStockNodeByAShareShortName is Ok. But the second getStockNodeByQueryProperty is failed. Is there any method to generate dynamic property keys in n.{xxx} or n.?1 or n.:xx ?
for creating dynamic property or dynamic query you need to use session(import org.neo4j.ogm.session.Session;) then you can create dynamic query and append your where condition
String query="match (n:stock) where" DYNAMIC_FIELD+"=" +VALUE
session.query(Map.class, query, queryParameters);

Can I derive ARRAY_CONTAINS from query method name in Spring Data Couchbase Repository?

I have a Couchbase-Document "Group" with a list of group-members-names. I want to query for all groups of one person. I managed to do it with N1QL ARRAY_CONTAINS - see in code example - but i hoped that i could generate the query from the method name as it is usual in Spring Data.
Any help is appreciated :)
I tried
public List<MyGroup> findAllByMembers(String member); and public List<MyGroup> findByMembers(String member); but they just return an empty list - i guess they try to match the whole "members" value and don't recognize it as a list -, no errors.
Code
My Document with a List field
#Data
#Document
public class MyGroup {
private String name;
private List<String> members = new ArrayList<>();
}
My Repository
#RepositoryDefinition(domainClass = MyGroup.class, idClass = String.class)
public interface MyGroupRepository extends CouchbaseRepository<MyGroup, String> {
//#Query("#{#n1ql.selectEntity} WHERE ARRAY_CONTAINS(members,$1) AND #{#n1ql.filter}")
public List<MyGroup> findAllByMembers(String member);
}
Expected
Given a "group1" with "member1" in members.
repository.findAllByMembers("member1"); should return ["group1"].
Couchbase is limited by the Spring Data specification. Unfortunately, we can't simply add new behaviors to it (if you switch to a relational database, it has to work with no breaking points). So, whenever you need to query something that has a N1QL specific function/keyword, you have to write a query via #Query

Spring Data JPA #Query with foreign key: Parameter not matched

I have a table "Signal" with id, volume and object_id columns.
Object_id is a foreign key. I need to retrieve each signal that has a particular object_id.
Im trying to use this Query
public interface SignalRepository extends JpaRepository<Signal, Integer> {
#Query("select s from Signal s where s.object = ?1")
Optional<List<Signal>> findSignalByObjectId(Integer objectId);
}
It doens't work. If I change "?1" to 1 it gets the hardcoded value. If I try to query the "volume", it works fine.
I get this error:
Blockquote
nested exception is java.lang.IllegalArgumentException: Parameter value [1] did not match expected type
I'd recommend you omit the query and let spring data generate one for you. So your case may be represented somehow like that (in case of proper relation mapping defined):
public interface SignalRepository extends JpaRepository<Signal, Integer> {
Optional<Signal> findByObject(YourObjectType object);
}
If you provide more info e.g. your entities - you can get more help.
You can use Spring data to generate the underlying query like this :
public interface SignalRepository extends JpaRepository<Signal, Integer> {
List<Signal> findSignalByObjectId(Integer objectId);
}
or you can write the query with this return type and parameter:
public interface SignalRepository extends JpaRepository<Signal, Integer> {
#Query("select s from Signal s where s.object = :id")
List<Signal> findSignalByObjectId(#Param("id") Integer objectId);
}

Get parameters out from QueryDSL Predicate Object

I use QueryDSL predicate object with a spring REST endpoint to retrieve and query param values.
#GetMapping("/{subjectId}/students")
#RolesAllowed( {Roles.PLATFORM_ADMIN, Roles.USER})
public List<StudentResponse> getAllStudents(#PathVariable final String subjectId,
#QuerydslPredicate(root = Student.class) final Predicate predicate) {
final Predicate searchPredicate = studentPredicate()
.predicate(predicate)
.subjectId(subjectId)
.build();
return studentService.findBySubjectId(subjectId, searchPredicate);
}
student Class contains studentId and studentName attributes;
Now, if someone invokes https://hostname/{subjectId}/students?studentId=1234&studentName=test
Then above code generates the predicate object with param values. But I need to get above 2 param values out from predicate object for further processing apart from the db querying. I don't see any supportive method from predicate object to retrieve values out. So how can I do it?
There is no straightforward way to do this.
However You can try this.
predicate.toString(); ---> This would print user.Studentid=1234 && user.studentName=test
From this, you can do a string split.
Another way is with
predicate.getClass()); ----> This will give you the class name like
class com.querydsl.core.types.PredicateOperation (in case of more than one query conditions)
class com.querydsl.core.types.dsl.BooleanOperation (in case of single query condition).
With this you could typecast predicate to corresponding type and then do getArgs().

Selecting fields on Spring Data

I'm trying to find information about how to select only certain fields of an entity using Spring Data (I'm using JPA). I want to select only specific information of an entity, the repository interfaces gives you the ways to return the information of the WHOLE entity!. Some times I only need 2 or 3 fields of an entity and returning 20,30, ...100.. fields may be a little overkill.
This kind of functionality is something that I would do using Hibernate Criteria Projections, or even JPA "SELECT NEW ...." queries. Don't know if it is possible with Spring Data.
Thanks.
What you can do is return a List<Object[]> from repository. Then in your service class iterate over this list and manually create the object you need. Sample repository method
#Query("select el.moduleId, el.threadId from ExceptionLog el")
public List<Object[]> tempQuery();
I think you can also do it in this way
SomeDataPOJO{
required col1
required col2
}
and then write query like this
#Query("select new SomeDataPOJO from requiredTable where xyz="abc")
public List<SomeDataPoJO> tempQuery()
Its not plain Spring Data but did you consider using Springs JdbcTemplate? Its also in the Context if you use Spring Boots Autoconfiguration and has several handlers for transforming results of the Query.
For Example for the Query SELECT a, b FROM EMPLOYEE WHERE ID = ? you could use
String query = "SELECT a, b FROM EMPLOYEE WHERE ID = ?";
List<Pair<String,Integer>> employees = jdbcTemplate.queryForObject(
query, new Object[] { id }, new ExampleRowMapper());
Where the ExampleRowMapper transforms each row from the result into your given Return type (Pair<String, Integer> in this case) and could look like
public class ExampleRowMapper implements RowMapper<Pair<String, Integer>> {
#Override
public Pair<String, Integer> mapRow(ResultSet rs, int rowNum) throws SQLException {
return Pair.of(rs.getString(1), rs.getString(2));
}
}
Example adapted from https://www.baeldung.com/spring-jdbc-jdbctemplate where you find more information.
Of course its not as typesafe as a JPQL as the Query is "raw" or "native" SQL but at least the response is again typesafe and I like it more than to return Object[] or something.

Categories

Resources