How to query upon the given parameters in Mongo repository - spring-boot

I have a mongo repostiory query as below, If we provide both name and price it gives the response. I want to get response if we only give name or price or both. how to make those parameters optional. if we provide both name and price i want to retrieve aggregated result unless i want to search just from the given field. Much appreciate you help.
List<Response> findByNameAndPrice(String name, int price)

Either you may need to implement custom JPA query or need to use QueryDSL in such scenarios.
1) Custom JPA Query like, you may need to change the query if you want to ad new optional parameters.
#Query(value = "{$or:[{name: ?0}, {?0: null}], $or:[{price: ?1}, {?1: null}]}")
List<Response> findByNameAndPrice(String name, Integer price)
2) QueryDSL Approach where you can add as many optional parameters, no need to modify your code. It will generate query automatically.
Refer this link for more : Spring Data MongoDB Repository - JPA Specifications like

I don't believe you'll be able to do that with the method name approach to query definition. From the documentation (reference):
There is a JIRA ticket regarding this which is still under investigation by the Spring team.
You can try this way
In repository
List<Response> findByName(String name)
List<Response> findByPrice(int price)
List<Response> findByNameAndPrice(String name, int price)
In your service file
public List<Response> findByNameAndPrice(String name, int price){
if(name == null ){
return repository.findByName(name);
}
if( price == 0){
return repository.findByPrice(price);
}
return repository.findByNameAndPrice(name, price);
}

Here I found a simple solution using mongodb regex,we can write a query like this,
#Query("{name : {$regex : ?0}, type : {$regex : ?1})List<String> findbyNameAndType(String name, String type)
The trick is if we want to query upon the given parameter, we should set other parameters some default values. As an example here thinks we only provide name. Then we set the type to select its all possible matches by setting its default param as ".*".
This regex pattern gives any string match.

Related

Getting Second Order SQL Injection in Spring Hibernate

I am facing Second Order SQL Injection in the Spring-Hibernate application after scanning through the Checkmarx tool, I have gone through multiple questions in StackOverflow and in other platforms as well but did not get the right finding.
could you please look into the below code snip,
public String getOrderId(order_name){
String returnId= null;
Query query = entityManager.createNativeQuery("select order_id from order where order_name=?");
List<String> dataset = query.setParameter(1,order_name).getResultList();
if(dataset!=null){
returnId = dataset. Get(0);
}
return returnId;
}
In this above method, while calling getResultList(), getting a high vulnerability issue that, this method returns data flows through the code without being properly sanitized or validated, and eventually used in further database query in the method.
Earlier code was like this,
public String getOrderId(order_name){
String returnId= null;
String q = "select order_id from order where order_name="+order_name;
Query query = entityManager.createNativeQuery(q);
and directly it was used as a string append in query, which I have modified with set parameter,
Query query = entityManager.createNativeQuery("select order_id from order where order_name=?");
List<String> dataset = query.setParameter(1,order_name).getResultList();
but still after getting data from query.getResultSet(), it is asking for sanitizing and validating the data before use in further database query method.
and this return data is being used in further query like select * from return_Data where clause. (properly used in where clause to set parameter to avoid SQL injection).
and in the above query is used in another method where we pass return_Data as input to it.
could you please help here to know what checks and validation can be added to overcome this type of issue. Thanks in advance for prompt response.

I want to create a search filter in Spring Boot controller, that takes 6 paramas and param value may be null then how to write a Data JPA Query?

Like I have a page where data are showing like first name, middle name, last name, address, city, state, country, age, salary.
There are a filter implemented that have 4 fields like city, age, salary, state. now I have to made a controller in Spring boot that takes all 4 fields as input params and find data from database using Spring Data JPA.
But my problem is that I want to filter Data sometime by salary only, sometime by city, state, sometime with all 4 params.
So what will be controller code and JPA Repository query to do this filter process.
Please Help me
Thanks in Advance
test if your parameters are null :
"where (:name is null or name = :name) and (:city is null or city = :city)"
I would suggest to use JPA Specification instead,
to know more on specification code here is my thread on stackoverflow
If you want to stick with JPA then here's the query which can help you
where (:field1 is null or table.field1 = :field1)
and (:field2 is null or table.field2 = :field2)
...
...
...
Explanation: The above code will check if the parameter is null, then return true otherwise compare with the column.
You can modify Query with below clause Where you can write query in Repository and in
where clause you can add conditions. So this will work as expected.
#Query(value = "SELECT user from User user WHERE ((:name IS NULL) OR (user.name = :name)) AND ((:city IS NULL) OR (user.city = :city)))

Spring And Kotlin Query

How can I achieve this query
select *
from table t
where name like '%Ami%'
order by (name = 'Ami') desc, length(col);
(just the sort part)
Using springframework Sort..
What I tried is
Sort.by(Sort.Direction.DESC, "name") // But I need to sort by name = 'Ami'
Sort.by(Sort.Direction.DESC, "name" = 'Ami'") // throws an error
JpaSort.unsafe(Sort.Direction.DESC, "name" = 'Ami'") // throws an error
Looks like the documentation has an example almost identical to your question:
https://docs.spring.io/spring-data/jpa/docs/2.4.5/reference/html/#jpa.query-methods.sorting
However, using Sort together with #Query lets you sneak in
non-path-checked Order instances containing functions within the ORDER
BY clause. This is possible because the Order is appended to the given
query string. By default, Spring Data JPA rejects any Order instance
containing function calls, but you can use JpaSort.unsafe to add
potentially unsafe ordering.

Spring Data JPA Use SpEL syntax to conditionally build query

I tried to build a query depending on a boolean #Param, and the difficulty is that I build the end of the query without using a classical operator ( = , <, > ...).
For the example, let's assume I want to fetch all my Sales objects that are not related to an Account object (if I pass false in #Param) or that are related to an Account (if I pass true in the #Param) :
#Query("SELECT sale ....
WHERE sale.account :#{isbound ? NOT NULL : IS NULL}")
public List<Sale> getSales(#Param("isbound") boolean isBound);
I tried a few syntaxs based on the official Spring documentation (https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions), but all their examples are working with an operator before the expression, like this: entity = #{the_expression}.
Does somebody once tried this and can give me the good way to write this ? thx !
Refactor your query code like bellow:
#Query("SELECT sale ....
WHERE (true = :isbound and sale.account is not null)
or (false = :isbound and sale.account is null)")
public List<Sale> getSales(#Param("isbound") boolean isBound);

Spring Data Rest - Sort by multiple properties

I have an entity as below
Class Person{
String id;
String name;
String numberOfHands;
}
With Spring Data Rest (Gosling Release Train), I'm able to specify
localhost/Person?sort=name,asc
for sorting name name ascending. Now, in a case where I need to sort by numberOfHands descending and name ascending. I'm able to specify
localhost/Person?sort=numberOfHands,name,asc
But, I'm not able to specify
localhost/Person?sort=numberOfHands,desc,name,asc
Is there a way to specify multiple sort order?
Thanks!
Solution (tl;dr)
When wanting to sort on multiple fields you simply put the sort parameter multiple times in the URI. For example your/uri?sort=name,asc&sort=numberOfHands,desc. Spring Data is then capable of constructing a Pageable object with multiple sorts.
Explanation
There is not really a defined standard on how to submit multiple values for a parameter in a URI. See Correct way to pass multiple values for same parameter name in GET request.
However there is some information in the Java Servlet Spec which hints on how Java servlet containers parse request parameters.
The getParameterValues method returns an array of String objects containing all the parameter values associated with a parameter name. ... - Java Servlet Spec, section 3.1
The sample further in that section states (although it mixes request and body data)
For example, if a request is made with a query string of a=hello and a post body of a=goodbye&a=world, the resulting parameter set would be ordered a=hello, goodbye, world.
This sample shows that when a parameter (a in the example) is presented multiple times the results will be aggregated into a String[].
Here is how to construct the multi Sort object manually/programatically.
Sort sort = Sort.by(
Sort.Order.asc("name"),
Sort.Order.desc("numberOfHands"));
return personRepository.findAll(sort);
Note: This solution does not directly solve the original question asked, but may help visitors that landed on this question while searching for a solution how to sort on multiple properties from a backend perspective / in a somewhat "hardcoded" way. (this solution does not require/take any URI parameters)
When dynamic fields are there then you simply do match with fields and add in sorting list like.
List<Sort.Order> sorts= new ArrayList<>();
if (sort == "name" && sortingOrder.equalsIgnoreCase("DESC")) {
sorts.add(new Sort.Order(Sort.Direction.DESC,"name"));
} else if (sort == "numberOfHands" && sortingOrder.equalsIgnoreCase("DESC")) {
sorts.add(new Sort.Order(Sort.Direction.DESC,"numberOfHands"));
}
return personRepository.findAll(Sort.by(sorts));
If you are using Pagination then directly add in PageRequest Request.
return personRepository.findPersons(PageRequest.of(pageNo, pageSize, Sort.by(sorts)));

Resources