I'm trying to find the solution for implementing search by keyword. Final API should look like /persons/search?keyword=test. The search should check several columns of persons table (firstName, lastName, school, ...).
In the result list, I need to have the list of persons which contains keyword at least in one column.
What will be the best solution to implement that by using Spring Data Rest?
Using #Query annotation on a repository, you can do something like this:
public interface PersonRepository extends CrudRepository<Persons, Long> {
#Query("SELECT p FROM Persons where LOWER(p.firstname) like :key%"
+ " or LOWER(p.lastname) like :key%" )
public List<Person> searchBy(#Param("word") String key);
}
NOTE: I did a similar thing, but I do not have the exact code right now, so just check out the syntax, but what I was able to achieve with this was the ability to search on multiple columns with a single key.
Related
Overview
Using QueryDSL, its possible to derive queries from the attributes contained in a Request query string. For example:
?firstname=Dave&lastname=Matthews
This query would search for users with firstname equal to Dave and Last name equal to matthews.
Problem
How do you use the LIKE operator? For example, suppose I want to fetch a list of users that have the lastname containing the word "Matt". Ive read solutions that propose to bind the fields and instead of using equals, use contains in all of them. This does solve the problem but creates another as it replaces the EQUAL operator. Other proposed solutions is to customize every repository with every possible field of the class, as in : Querydsl web with contains
Current solution
The current solution I have is to search using equals, it does not solve the problem. It does not work with LIKE, CONTAINS, or anything of the sort. So basically I have the method below:
#RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model,
#QuerydslPredicate(root = User.class) Predicate predicate,
Pageable pageable) {
model.addAttribute("users", repository.findAll(predicate, pageable));
return "index";
}
Another Topic in Stackoverflow
The following topic
How can you use different operators with QueryDSL Web?
Approach a similar issue however using another operators as example. The proposed solution by the user Geert Graat, is to use the library Spring Data QueryDSL Value Operators, which can be found at : https://bitbucket.org/gt_tech/spring-data-querydsl-value-operators/src/master/
However, some questions remain:
A) Is it still valid to 2022?
B) Is this the only and proper solution?
References
https://www.logicbig.com/tutorials/spring-framework/spring-data/query-dsl-web-support.html
https://www.logicbig.com/tutorials/spring-framework/spring-data/web-query-dsl-collection-properties.html
https://gt-tech.bitbucket.io/spring-data-querydsl-value-operators/README.html
https://bitbucket.org/gt_tech/spring-data-querydsl-value-operators/src/master/
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web.type-safe
I am able to search for a keyword in a column using
List<Application> findByProposalContainingIgnoreCase(String keyword);
How can I achieve the same using a list of keywords?
For example:
List<Application> findByProposalContainingIgnoreCase(List<String> keywords);
UPDATE:
If it is not possible to do so, is the below way effective:
#Autowired
private ApplicationService applicationService;
List<Application> applications = new ArrayList<>();
for (String keyword : keywords) {
applications.addAll(applicationService.findByProposalContainingIgnoreCase(keyword));
}
It's not possible as normal sql cannot do it either. The use of the word 'like' implies searching for all the possibilities that contain the keyword provided. In your case you'd have to string multiple contains statements together like
List<Application> findByProposalContainingIgnoreCaseOrProposalContainingIgnoreCase(String keyword1, String keyword2);
You might be better of doing the inkeyword for your list
List<Application> findByProposalIn(Set<String> proposals);
The problem arises though that now you would have to add both uppercase and lowercase of the proposal to the set as it might not be case sensitive, and it will look for the exact matches not part of the word. Its not ideal but I think it'll work for what you're trying to do.
UPDATE
You're answer by adding the for loop would suffice for what you need.
I want to find persons that have similar name according to a provided list of name and age like in the following spring repository statement.
Page<Person> findByNameContainingInAndAge(Pageable pageRequest, Collection<String> listOfNames, Integer age);
I tried it but not working. How can I fix it?
Spring Data may not support all possible queries. Sometimes you have to create a custom one. Try something like this:
#Query("SELECT p FROM Person p WHERE p.name IN (:listOfNames) and p.age = :age ")
public List<Person> findByNameContainingInAndAge(#Param("listOfNames") Collection<String> listOfNames, #Param("age") Integer age);
I tried many combinations of "IN" and "Containing" on same field, but not worked. Finally, I concluded that theoretically, the repository statement mentioned in the question is not possible. Because the "CONTAINING" keyword accepts only one value for the field and the "IN" keyword accepts a collection of values for the field "name". So, applying both keywords on single field at same time in a single repository statement is not possible.
I have a PagingAndSortingRepository:
public interface BrowserLinkPagination extends PagingAndSortingRepository<BrowserLink, Long> {
List<BrowserLink> findByUserAndUriLike(User user, String uri, Pageable pageable);
}
Now what I want to do is to search for multiple words in the uri column. Like comes pretty close, but it is order dependent on how the words occur in the string.
EDIT for clarification: Order dependences is exactly what I not want. I want the search strings to be independent of order, so LIKE is not what I am looking for.
I guess this is pretty common to find, having several search terms to look for in a string, I know I could implement it by providing the SQL to execute, but I am curiuous if there is a way to express that in terms of spring data? am
I am using postgresql for production and h2 for development / tests.
After reading more about the topic it is kind of obvious I need some kind of fulltext search.
I will start using the one provided by postgresql. I found a short working example: http://rachbelaid.com/postgres-full-text-search-is-good-enough/
Thanks for the comments.
Use In in method name. In Your case it could look like that:
public interface BrowserLinkPagination extends PagingAndSortingRepository<BrowserLink, Long> {
List<BrowserLink> findByUserAndUriIn(User user, List<String> uri, Pageable pageable);
}
When You are using the standard API created by Spring, the usage from the browser URI is pretty simple - just type in the address:
/your_api/browserlink/search/findByUserAndUriIn?user=xxx&uri=uri1,uri2,uri3
I have a Java class that has a field which is a list of strings. The elements in the list will vary between objects, but I need to determine a list of distinct values for the field. The Java class looks something like this:
public class POJO implements Serializable {
#ElementCollection
private List<String> listOfStrings;
}
JPA creates new table called POJO_listOfStrings, and I could run a SQL query like
SELECT DISTINCT string FROM dbo.POJO_listOfStrings
to get the information I need. I'm at a loss how to do this the correct way with JPQL. Things like "SELECT DISTINCT s FROM POJO.listOfStrings s" do not work. Any help is greatly appreciated.
Distinct on an entity object doesn't work on simple select, you need to specify the element in entity which you want to retrieve distinct.
Similar post in below link should give an insight to it.
How do you create a Distinct query in HQL