I'm writing an app using Spring Boot, Spring Data. And I'm trying to implement a filtering feature based on different filter parameters.
Using Spring Data queries we can define quite complex logic, e.g.:
#Query("SELECT u FROM User u WHERE u.status = 1")
Collection<User> findAllActiveUsers();
But what if the number of where clauses, order, limit, number of different parameters are unknown till we make an actual filter request which can be quite complex.
Right now filter params are send in a json object which I parse and retrieve them and the result sql query can be something like this:
SELECT * FROM table
WHERE field1 != `value1` and (field1 != ` value2 `OR (field1 = `value3` AND filed2 < 3))
AND field2 != 99
Is it possible to generate dynamically complex queries with undefined (till the actual filter request, during runtime) number of params, where clauses and other stuff?
I use this active project RSQL for JPA
https://github.com/perplexhub/rsql-jpa-specification
Sometime back I wrote an article on Spring Data JPA Query with Dynamic Where Clause. In this example you can send a Where Clause and Map of parameters for that. You can make use of this and modify it a bit suit your needs.
I would suggest using Spring JPA Specification
ref : https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
To build it in a type safe manner, you can use FluentJPA.
Related
I have a Spring Data REST service with a single #Entity and Repository. When I run
$ curl localhost:8080/api
I get all the data stored in my repository and it works as expected. I also have a small React front end and I display that data there.
My question is: Where should I filter the data? For example maybe I want all the entries with id > 10. Should I just filter the response in my front end or should I make the REST call in such a way that it returns just the required entries?
If I should do the latter, then how?
Thanks.
Filter in the backend or - more specifically - with the database query.
The database is optimized for those operations. Thus, you can reduce the data transmitted from the backend to the frontend and reduce the load on the frontend since only data that is requested by the user will be processed by the frontend.
Another benefit is that if you have multiple frontends (e.g. website & mobile app), you have to implement filter functionality only once (in the backend) instead of twice (in each client)
If it is always the case, why would you put extra burden on front-end shoulders to filter the results all the time?
Implement a new method which returns the desired results(e.g id > 10) and annotate it with #Query and provide JPQL or native query inside it
#Query("SELECT c FROM Customer c WHERE c.id > 10")
Collection<Customer> findAllActiveCustomers();
However, if you choose native query do not forget to put nativeQuery = true inside #Query
I want to get all the values from a particular column in JPA and store all values into a list. currently, I am using the below approach but I am getting records in something else format.can someone please help me out
Query q1 = factory.createNativeQuery("select * from booking_attendee where booking_id="+id);
List<String> em1=q1.getResultList();
return em1;
query otput
em=[[Ljava.lang.Object;#68606667, [Ljava.lang.Object;#2cd7f99a, [Ljava.lang.Object;#137a5a5, [Ljava.lang.Object;#a45cc1c, [Ljava.lang.Object;#61fdc06d, [Ljava.lang.Object;#72f5eee1, [Ljava.lang.Object;#4e536797]
If you want to create a native query for this, it is more about how to solve this in SQL. You do not say SELECT * which means all columns. You would have to say SELECT your_column_name to select only a specific column.
Query q1 = factory.createNativeQuery("SELECT your_column FROM booking_attendee");
List<String> em1 = q1.getResultList();
The WHERE clause could and should be defined with the parameter binding of JPA. There are several advantages concerning performance and SQL injection.
Named parameter binding is special to the persistence provider (e.g. Hibernate). The common way for JPA is using ? to let your code be portable to other providers.
Query q1 = factory.createNativeQuery("SELECT your_column FROM booking_attendee b WHERE b.booking_id = ?");
q1.setParameter(1, id);
List<String> em1 = q1.getResultList();
Native queries offer the possibilities to use original SQL. Like this, some features which are specific for your database could be used with this. Nevertheless, if you do not have very specific SQL code, you should also have a look in JPQL, the specific query language of JPA, and the JPA Criteria API which offers advantages when you want to refactor your code, shows errors during compile time and makes the dynamic creation of queries easier.
I am struggling with a mongo query. I need to find a collection of documents in single query. The collection should contain document with newest date (field createdAt) for every user in single query.
There is a test case in Spock to demonstrate what I am trying to acheive:
def 'should filter the newest location for every user'() {
given:
List locationsInDb = [
buildLocation(USERNAME_1, '2017-02-03T10:37:30.00Z'),
buildLocation(USERNAME_1, '2017-03-04T10:37:30.00Z'),
buildLocation(USERNAME_2, '2017-02-05T10:37:30.00Z'),
buildLocation(USERNAME_2, '2017-03-06T10:37:30.00Z')
]
insertToMongo(locationsInDb)
when:
List filteredLocations = locationRepository.findLastForEveryUser()
then:
filteredLocations == [locationsInDb.get(1), locationsInDb.get(3)]
}
I found that distinct methods are a part of 2.1.0.M1 version so they are not available yet.
I was also trying with #Query annotation but the documentation (link below) does not specify how to create a query like mine.
https://docs.spring.io/spring-data/data-document/docs/current/reference/html/#d0e3309
Thanks for your help.
There are no means to express the query you are looking for via a derived query in Spring Data, nor using the MongoDB native query operators. Distinct as well will not do the job as it just extracts distinct values of a single field into an array.
Please consider using an Aggregation. Spring Data specifics can be found in the reference documentation.
I am using Spring Data JPA with QueryDSL and trying to use Sum function in where condition, As i am using pagination so i have to get count first.
So i have java code like below :-
NumberPath<Double> path = entityPath.getNumber("qty", Double.class);
BooleanExpression exp = path.sum().loe(120);
JPQLQuery countQuery = from(stock).where(exp);
long count = countQuery.count();
its creating query like this :-
select count(stock0_.stock_id) as col_0_0_ from stock stock0_
where sum(stock0_.qty)>=120;
and i am getting Error Code: 1111. Invalid use of group function.
above query is not working in SQL as well because sum function cant be use with count in where condition. I have not idea how to deal with such problem when i have to get count first and then fetch the real data.
Can someone please help me out with what is JPA approach to deal with such issue.
Please don't suggested #Query annotation because i can not use it. Due to dynamic filtration requirement.
You are using aggregate functions (sum). Then you need having() instead where()
This example is a really large one. You only need to care about pagination and having elements.
If you got different predicates and a pageRequest object.
Page request example:
pageRequest = new PageRequest(
MI_PAGE,
LIMIT,
Sort.Direction.valueOf( ASC ),
ORDER_FIELD);
EntityQ represents a QueryDSL generated meta-entity.
Query example:
new JPAQuery(em).from(entityQ).where( entityQ.id.in(
new JPASubQuery()
.from(entity2Q).innerJoin(entity2Q.objEntityQ, entityQ)
.where(ENTITY, PREDICATE)
.groupBy(entity2Q.objEntityQ.id)
.having( Wildcard.count.goe(SIZE) )
.list(entity2Q.objEntityQ.id)
))
.offset(pageRequest.getOffset() )
.limit( pageRequest.getPageSize() )
.orderBy(ORDERS).list(entityQ);
EDIT 2 More specific for your example:
I usually have a persistence context in my custom repositories:
#PersistenceContext
EntityManager em
Then, you could create a simple JPAQuery:
new JPAQuery(em)
.from(YOUR_STOCK_QUERYDSL_ENTITY)
.groupBy(YOUR_STOCK_QUERYDSL_ENTITY.field_to_sum)
.having(YOUR_STOCK_QUERYDSL_ENTITY.field_to_sum.sum().as("alias")
.goe(100));
I have to create a query in our backend application using the parameters obtained from the client. Consider this diagram:
I have entities (Type field), those entities' fields (Parameter), a relation, a value and an operand. So in sql terms the table above translates to this:
... WHERE Item.reach_complience = ”<1%”
and Item.technical.type = ”RES”
and Item.technical.value <= ”1k”
and Item.technical.value >= ”4K7”
and (Item.technical.footprint = ”RC0603” or Item.technical.footprint = ”RC0805”)
and Item.classification.incurrent_handling = ”prefered-to-use”
I really don't want to reinvent the weel here, so my question is:
Is there a Criteria factory libarary which uses JPA or more specifically Hibernate or is there some 3rd party library which can be used to create criteria queries? We are using Eclipse RCP on the frontend and data arrives to the backend (Spring) through an Apache Cxf service. I wish to write maintainable using JPA's query syntax.
Yes. I think ISearch is the best: http://code.google.com/p/hibernate-generic-dao/wiki/Search