Fetching only first/last element using Spring Data JPA and #Query annotation - java

EDIT: Solutions to this problem are provided in the second and fourth answer regarding this question setMaxResults for Spring-Data-JPA annotation?
Goal: Fetch the largest/smallest element by property z using a Spring Data JPA repository and the Spring Query annotation.
What I have so far
#Query("SELECT xelement FROM x xelement ORDER BY xelement.z")
public List<X> findFirstElement();
Problem: This query fetches all elements (which is not really effective). If I would use the EntityManager direcly, I could set the number of results using
entityManager.setMaxResults(1)
to only get the first element.
Question: How do I specify the maximum number of results using the #Query annotation?
Idea: Is using a PageRequest of size 0 the way to go?
Constraints: I am aware of the "FindFirstBy...." query feature but I want/have to use the #Query annotation.

You can use the limit property of sql just by adding nativeQuery to #Query annotation. However, there is another and a better way of doing this. Pageable class in your repository method will solve your problem without touching your #Query annotation:
#Query(value = "SELECT xelement FROM x xelement ORDER BY xelement.z")
List<X> findFirstElement(Pageable limit);
To set the limit and offset, use should call this repository method as follows:
List<X> xValues = xRepository.findFirstElement(new PageRequest(0, 1));
Here 1 corresponds to the limit which you want.
UPDATE (SPRING DATA 2.0)
Use PageRequest.of(0, 1) instead of new PageRequest(0, 1)

The closest JPA query syntax I can think for your use case is findFirstByZIsNotNullOrderByZAsc. This should eliminate the need to write custom native query.

Try to do this:
#Query(value = "SELECT xelement FROM x xelement ORDER BY xelement.z LIMIT 1",
nativeQuery = true)

Related

How can I obtain the first row from a SELECT operation using JPQL?

I have a database with data about some tests, I want to order them decently using their attribute DATE and take only the first one of all of them. I mean, the equivalent TOP 1 of SQL in JPQL.
Thanks for your help!
In spring jpa you can do something like this
Foo findTopByOrderByDateDesc(); //This will return 1st item
List<Foo> findTop10ByOrderByDateDesc(); //This will return top 10 item
For reference Spring Jpa Doc
You normally set that on the Query object before triggering the fetch:
entityManager.createQuery("...")
.setMaxResults(1)
.getResultList();
With the use of Spring Data Jpa syntax you would use something like:
Optional<Test> findFirstByOrderByDateDesc();
Or using Pageable:
Page<Test> test = repository.findAll(
PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "date")));
Mostly common
Foo findFirstByOrderByDateDESC();
Using #Query with nativeQuery = true
#Query(value="SELECT 1 * FROM "TableName" ORDER BY "DATE in db" DESC LIMIT 1", nativeQuery = true)
Foo findFirstByOrderByDateDESC(Long id); // name can be random
In Spring Data JPA, use the keywords first or top, both are semantically the same, i prefer top, because there are 2 less letters to type ;-).
Foo findTopByOrderByDateDesc(); //Top 1 assumed
Foo findFirstByOrderByDateDesc(); //First 1 assumed
If you want to find the first X rows, where X is a number, use:
List<Foo> findTopXByOrderByDateDesc();
List<Foo> findFirstXByOrderByDateDesc();
If you want to remember to deal with null returns, wrap the result in an Optional:
Optional<Foo> findTopByOrderByDateDesc();
Optional<Foo> findFirstByOrderByDateDesc();
The question specifically asks how to do it in JPQL. The answer is that you can't. You either need to use a JPA query derived from a method name (as in jumping_monkey's answer) or use a native query.

Spring Data: limit result for custom query

In my Spring Data repository I (have to) use custom queries using the #Query annotation. I know I can limit the number of results in a named query like that
Iterable<Person> findFirst5OrderByLastName()
or that it is possible to limit the number of results by passing a pageable like that
Iterable<Person> findByLastName(String lastName, Pageable pageable)
But is it possible to achieve the same when using a custom #Query annotation?
TIA
EDIT
as I see my question is a little confusing, some clearification:
What I want is to limit the number of the results I get, when using a custom query, so that I neither
1) need to specify the result-size through a pageable
2) need to use a named query to specify the result-size
In fact I want the limitation of the number of results to be completely transparent when invoking method (hence not passing a Pageable) and to not rely on the naming-scheme of Spring Data (as the meaning/function of the method is best conveyed through a custom name)
You can try this:
#Entity
#Table(name = "persons")
public class Person {
//...
}
#Query(value = "select * from persons limit 50", nativeQuery = true)
List<Person> getFirst50();
Don't forget to check whether your SQL server supports the limit keyword.
Of course you can use #Query to order a result, it is an JPQL query e.g.
#Query("SELECT u FROM User u ORDER BY u.name ASC")
Further sorting can be done be either providing a PageRequest or using Sort directly.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.sorting
I would suggest to add "By" but without parameter, it would work:
List<Person> findTop100By();
You need to extend PagingAndSortingRepository
and add method
Page<Person> listAllByPage(Pageable pageable)
See the example
Hello you can try this
#Query("...")
List<YourDTO>getData(Pageable pageable)
In your serviceImpl
List<YourDTO> getData(){
int limit=10;
Pageable pageable = PageRequest.of(0, limit);
return this.repo.getData(pageable);
}
You should avoid nativeQuery

Counting query in spring-data-couchbase (N1QL)

I'm writing couchbase repository using Spring module and I'm trying to add my own implementation of count method using N1QL query:
public interface MyRepository extends CouchbaseRepository<Entity, Long> {
#Query("SELECT count(*) FROM default")
long myCount();
}
But it doesn't work:
org.springframework.data.couchbase.core.CouchbaseQueryExecutionException: Unable to retrieve enough metadata for N1QL to entity mapping, have you selected _ID and _CAS?
So my question is: how can I write counting query using spring-data-couchbase?
I cannot find anything about this in spring documentation. link
This exception happens because the #Query annotation was designed with the use-case of retrieving entities in mind. Projections to a scalar like count are uncovered corner cases as of RC1. Maybe I can think of some way of adding support for it through explicit boolean flag in the annotation?
Unfortunately I was unable to find a workaround. I was trying to come up with a custom repository method implementation but it appears support for it is broken in 2.0.0-RC1 :(
edit:
The use case of simple return types like long, with a SELECT that only uses a single aggregation, should work so this is a bug/improvement. I've opened ticket DATACOUCH-187 in the Spring Data JIRA.
#Query("SELECT count(*) , META(default).id as _ID, META(default).cas as _CAS FROM default")
Change your query to this one.
Use this query :
#Query("SELECT count(*) as count FROM #{#n1ql.bucket} WHERE #{#n1ql.filter} ")
long myCount();

Spring java MongoDB #Query annotation for order top or first records

I use #Query annotation and crudRepository to fetch data from MongoDB.
Example:
#Query("{$query: id: ?0}, $orderby: {dateTime: -1}}")
public List<A> findId(
Integer id, Pageable pageable
);
What do I need to add to my #Query notation if i want to fetch only first N records of collection, or only top N records of collection? I would like to use dynamic query and dynamic set limit and order (first or top records).
you can append your #Query with $limit : 10, or rename your method like : find First10ByDateDesc()
Use the variable sort of the #Query:
#Query(value = "{}", sort = "{ _id : -1 }")
As an example for "order by id desc".

Spring data mongoRepository Query sort

I was looking to see how I could introduce a sort into a Query annotation in a repository method that I have.
I already saw this code in Google and here, but I could not make it works
#Query("find({state:'ACTIVE'}).sort({created:-1}).limit(1)")
Job findOneActiveOldest();
#Query("{ state:'ACTIVE', $orderby: {created:-1}, $limit:1 }")
Job findOneActiveOldest();
I know that with pagination I can make it, but in some cases I don't need paginate, so I was wondering how to make it with Query annotation.
Any suggestion please?
I don't think it is possible to do it with #Query annotation. If you dont need to paginate you can just make your repository method use Sort parameter:
#Query("{ state:'ACTIVE' }")
Job findOneActive(Sort sort);
and use it:
yourRepository.findOneActive(new Sort(Sort.Direction.DESC, "created"))
Just use sort parameter of #Query annotation. 1 = ASC, -1 = DESC
#Query(
value = ...,
sort = "{'details.requestTime': -1}"
)
if you also want to have pagination then use Pageable as method argument instead of Sort. Try below code:
#Query("{ state:'ACTIVE' }")
Job findOneActive(Pageable pageable);
yourRepository.findOneActive(new PageRequest(0, 1, new Sort(Sort.Direction.DESC,"created")));

Categories

Resources