Spring data query method creation - spring-data

What is the correct way to query on login field for both Sender and Receiver (Sender and Receiver are instances of the same object type)
Page<Message> findBySenderLoginOrReceiverLogin(String login, Pageable pageable);
Thanks

Query method creation is extensively explained in the official docs.
As #Marc Tarin suggested this answers my question:
Page<Message> findBySenderLoginOrReceiverLogin(String SenderLogin, String ReceiverLogin, Pageable pageable);

Related

Spring Mongo query not ignoring case

I've the following query that is not ignoring case. What could be done to make this be case insensitive?
#Query("{'occasionId':?0,'text':/.*?1.*/}")
Page<FreeMessageCard> findByOccasionIdAndTextIgnoreCase(String occasionId, String text, Pageable pageable);
If you use #Query annotation, spring-data will not generate another query based on the naming convention for method names. If you want it to generate a query for you - don't use #Query annotation. Besides that, you can make your query work by doing this:
#Query("{'occasionId':?0,'text':/.*?1.*/i}")
Page<FreeMessageCard> findByOccasionIdAndTextIgnoreCase(String occasionId, String text, Pageable pageable);

Spring Boot Couchbase Reactive isn't supporting Pagination

I'm trying to implement Pagination in my Reactive WebFlux app and my DB is Couchbase.
The Spring Data Couchbase doc allows me to pass Pageable as an argument in my Repository.
Flux<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable);
However, when I try to implement it I get the below error:
Caused by: java.lang.IllegalStateException: Method has to have one of the following return types! [interface org.springframework.data.domain.Slice, interface java.util.List, interface org.springframework.data.domain.Page]
My Repository method looks like this:
Flux<Building> findAll(Pageable pageable);
However, if I use this workaround, I've no problem.
#Query("#{#n1ql.selectEntity} where #{#n1ql.filter} LIMIT $1 OFFSET $2")
Flux<Building> findAll(Integer limit, Integer offset);
Is this a bug? Or, am I using it wrong?
Spring Boot version: 2.2.7.RELEASE
Full Repository:
#Repository
public interface BuildingRepository extends ReactiveSortingRepository<Building, String> {
#Query("#{#n1ql.selectEntity} where #{#n1ql.filter} LIMIT $1 OFFSET $2")
Flux<Building> findAll(Integer limit, Integer offset);
//This works if I comment the below
Flux<Building> findAll(Pageable pageable);
}
The short answer is that the documentation is not current, and the best solution is to implement paging yourself with limit and offset as you have done. There is work underway to remedy this in https://jira.spring.io/browse/DATACOUCH-588 (it's not described there, but that's the tracking issue)
Even so, a more efficient way of paging is key-set pagination ( https://use-the-index-luke.com/no-offset ) - but you’ll need to implement that in your application. It uses the indexes to get the items beginning with the first one required, instead of “skipping” over the ones in prior pages.

How Slice<?> in JPA repository works?

We need to send Pageable object that is fine.
We will use slice mainly if in UI you don't need to send no of pages, only prev & next.
But, how it internally works?
Page<Employee> findByFirstName(String firstName, Pageable pageable);
Slice<Employee> findByFirstName(String firstName, Pageable pageable);
Page will internally call query & again the same query with
SELECT COUNT(*) FROM (last query) to find total elements.
Similarly, what Slice's queries?
It is the same as for Page except that it doesn't perform the count.
It might be of interest that the paging, i.e. the limiting to a certain batch of the result is done by calling setFirstResult(int) and setMaxResult(int)

Spring JPA findByColumnNameLike not working

I have a method -> findByfileNameLike(fileName,1, pageable) and its declaration in a repository that extends JPA Repository is
#Query(value = QUERY)
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
#LogExecutionTime
Page<BatchDTO> findByfileNameLike(String
fileName,#Param("departmentId")Integer departmentId, Pageable pageable)
Query is Select new DTO(bdm.id.batch.status) from Table bdm where bdm.id.departmentId =:departmentId and bdm.id.batch.status <> 7";
I want to filter the query by the column fileName.I have read to give the method name as given according to the doc of spring data jpa.But its not working.
Where and how will i give the fileName to be filtered?Should it be first parameter in the method?
Once you specify a query using the annotation #Query, Spring data jpa will not automatically create a query for you based on the method name and it will rely on the query provided by using the annotation.
The method findByfileNameLike will not make any difference here as a query is provided explicitly. Hope that answers your question

Is it possible to use SpringData MongoDB repository to execute an arbitrary query, with pagination?

We have a use case where a user can pass in arbitrary search criteria for a collection, and wants the output paged. Using Spring Data repositories, this is quite simple if we know ahead of time what attributes they may be searching on by simple extending MongoRepository, and declaring a:
Page<Thing> findByFooAndBarAndBaz(Type foo, Type bar, Type baz, Pageable page)
However, if we generate the query ourselves either using the fluent interface or constructing a mongo string and wrapping it in a BasicQuery class, I can not find a way to get that into a repository instance. There is no:
Page<Thing> findByQuery(Query q, Pageable page)
functionality that I have been able to see.
Nor can I see how to hook into the MongoTemplate querying functionality with the Page abstraction.
I'm hoping I don't have to roll my own paging (calculating skip and limit parameters, which I guess is not hard) and call into the template directly, but I guess I can if that's the best choice.
I don't think this can be done in the way I'd hoped, but I've come up with a workaround. As background, we put all our methods to do data access in a DAO, and some delegate to the repository, some to the template.
Wrote a DAO method which takes our arbitrary filter string (which I have a utility that converts it to standard mongo JSON query syntax.
Wrap that in a BasicQuery to get a "countQuery".
Use that countQuery to get a total count of records using MongoTemplate#count(Query, Class)
Append my paging criteria to create a "pageQuery" using Query#with(Pageable)
Run the pageQuery with MongoTemplate#find(Query, Pageable)
Get the List<T> result from that, the Pageable that was used for the query and the count returned from the countQuery run, and construct a new PageImp to return to the caller.
Basically, this (DocDbDomain is a test domain class for testing out document db stuff):
Query countQuery = new BasicQuery(toMongoQueryString(filterString));
Query pageQuery = countQuery.with(pageRequest);
long total = template.count(countQuery, DocDbDomain.class);
List<DocDbDomain> content = template.find(pageQuery, DocDbDomain.class);
return new PageImpl<DocDbDomain>(content, pageRequest, total);
You can use the #Query annotation to execute an arbitrary query through a repository method:
interface PersonRepository extends Repository<Person, Long> {
#Query("{ 'firstname' : ?0 }")
Page<Person> findByCustomQuery(String firstname, Pageable pageable);
}
Generally speaking, #Query can contain any JSON query you can execute via the shell but with the ?0 kind of syntax to replace parameter values. You can find more information on the basic mechanism in the reference documentation.
In case you can't express your query within the #Query-Annotation, you can use the Spring Repository PageableExecutionUtils for your custom queries.
For example like this:
#Override
public Page<XXX> findSophisticatedXXX(/* params, ... */ #NotNull Pageable pageable) {
Query query = query(
where("...")
// ... sophisticated query ...
).with(pageable);
List<XXX> list = mongoOperations.find(query, XXX.class);
return PageableExecutionUtils.getPage(list, pageable,
() -> mongoOperations.count((Query.of(query).limit(-1).skip(-1), XXX.class));
}
Like in the original Spring Data Repository, the PageableExecutionUtils will do a separated count request and wrap it into a nice Page for you.
Here you can see that spring is doing the same.