SortBy Spring Data MongoDb - mongodb

I have passed my query from postgres to mongodb, everything is correct. But in the ordering I do not see how to integrate it within #Query as in the example sql
// sql-postgres ( repository )
#Query("select c from ClienteElser c where c.securityDomainId IN (2,10) and c.deleted is null order by c.razonSocial")
//mongodb ( repository )
#Query("{security_domain_id: { $in: [2,10] },'deleted':null}")
public List<Cliente> findAllByOrderByRazonSocialAsc(Sort sort);
//service
Sort sort = new Sort(Sort.Direction.ASC, "razon_social");
List<Cliente> result = clienteRepository.findAllByOrderByRazonSocialAsc(sort);
At the moment I have fixed it like that, but I would prefer it to be inside #Query
And order giving priority to capital letters, I do not know how to avoid that. Example : "ACS" is before "Abalos"
Can someone help me to integrate the sort within #Query with mongodb and that does not differ between uppercase and lowercase
Thank you

This has been adressed in DATAMONGO-1979 for the Lovelace release (aka Spring Data MongoDB 2.1.0).
It will allow to set a default sort for repository query methods via the #Query annotation.
#Query(sort = "{ age : -1 }")
List<Person> findByFirstname(String firstname);
Using an explicit Sort parameter along with the annotated one allows to alter the defaults set via the annotation. The method argument Sort parameters will be added to / or override the annotated defaults depending on the fields used.
#Query(sort = "{ age : -1 }")
List<Person> findByFirstname(String firstname, Sort sort);

Related

updateQuery returns 1 but it's not getting reflected in db (spring data jpa)

But updation works with below code snippet
Department department= departmentRepository.findOne(300L);
department.setName("rajiv");
departmentRepository.saveAndFlush(department);
but then this scenario being onetone mapping it could be a case where i would end up hitting 3 queries which include 2 select queries and one one update query .
To optimize the way i update it i'm trying to use this approach which is not getting updated thought executeUpdate() returns affected row as 1 .
There is a small mistake in your query.
You have used the = operator instead you should have used the like operator
You can also take help of #NamedNativeQueries
Example
DepartmentRepository.java
#Query(nativeQuery = true)
public List<Department> update(Long id);
Department.java
#SqlResultSetMapping(name="updateResult", columns = { #ColumnResult(name = "count")})
#NamedNativeQueries({
#NamedNativeQuery(
name = "Department.update",
query = "UPDATE departmemnt SET name like 'rajiv' WHERE id = ?",
resultSetMapping = "updateResult")
})
NativeQueries works more faster than normal Hibernate Queries
Yeah may this would help , in case of spring data i found a way to make it updatable and since they insist to use #transactional and extend the functionality of jparepository and now it hits only one line of statement
#Modifying(clearAutomatically = true)
#Transactional(readOnly=false)
#Query("update Department d set d.name =:name where d.id=:id")
int update(#Param("name")String name,#Param("id")Long id);
in case if i choose to for nativeQuery
#Modifying(clearAutomatically = true)
#Transactional(readOnly=false)
#Query(value="update Department d set d.name =:name where d.id=:id",nativeQuery=true)
int update(#Param("name")String name,#Param("id")Long id);

How to avoiding AND condition if parameter is null in Spring Data JPA query

I am trying to get the result of one query using Spring Data JPA. Here I am sending some parameter and receiving result according to that.
My repository query is,
#Query("select u.username,p.pname from Users u join u.priviJoin p where u.username = :uname AND p.pname = :pname")
List<Users> findByUsername(#Param("uname") String uname , #Param("pname") String pname );
And calling from controller like the following,
#RequestMapping(value = "/joinResult", method = RequestMethod.GET)
public List<Users> joinResultShow()
{
return (List<Users>) userRepo.findByUsername("test_user","testRole");
}
Here we can see that if I am passing some value then only checking according to that parameter. Here I need to modify my query like if parameter is null, then not need to use AND condition in query.
How can I modify this query for avoiding AND condition if parameter is null? I am new to Spring Data JPA world.
Here are some possible options for you
1. Create multiple methods in your repository like
#Query("select u.username,p.pname from Users u join u.priviJoin p where u.username = :uname AND p.pname = :pname")
List<Users> findByusernamewithRole(#Param("uname") String uname , #Param("pname") String pname );
#Query("select u.username,p.pname from Users u join u.priviJoin p where u.username = :uname")
List<Users> findByUsernameWithoutRole(#Param("uname") String uname);
Write a custom respository and use EntityManager. With this you can create a dynamic queries based on your input using CriteriaBuilder and use this criteria in querying.
Last and the most preferred option in case of dynamic inputs(like you have) is Querydsl.
Some articles about querydsl
http://www.baeldung.com/querydsl-with-jpa-tutorial
http://www.querydsl.com/static/querydsl/latest/reference/html/ch02.html

I am trying to use dynamic order by but the list retrieved is not ordered

public List<Series> findSeries(int period, String fieldname, int num) {
TypedQuery<Series> query = em.createQuery(
"select s from Series s where s.period = ?1 order by ?2",
Series.class);
query.setParameter(1, period);
query.setParameter(2, fieldname);
query.setMaxResults(num);
return query.getResultList();
}
This is the method I am using. I think order by isn't even getting executed, it doesn't give any error even when I pass incorrect fieldname.
When it comes to dynamic limit and ordering, its best to use PagingAndSortingRepository so now my Repository extends this repository. I can simply use JPA criteria query as below.
If u want to learn more about JPA criteria query i found this very helpful http://docs.spring.io/spring-data/data-jpa/docs/1.0.x/reference/html/#jpa.query-methods.query-creation
#Repository
public interface SeriesRepository extends PagingAndSortingRepository<Series,Long>{
List<Series> findByPeriod(int period, Pageable pageable);
}
And then when I call this method from my dao i can just instantiate PageRequest which is one of the implementation of Pageable. I can add limit and sorting order to this instance.
public List<Series> getSeriesByFilter(int period, String fieldname, int num) {
Sort sort = new Sort(Sort.Direction.ASC, fieldname);
Pageable pageable = new PageRequest(0, num, sort);
return seriesRepo.findByPeriod(period, pageable);
}
You cannot pass variables as column name in order by.
There is a work around which may help you achieve what you are trying.
public List<Series> findSeries(int period, String fieldname, int num) {
String query = "select s from Series s where s.period = "+period+" order by "+fieldname;
return entityManager.createQuery(query).getResultList();
}
Check this question Hibernate Named Query Order By parameter
There are ways to pass column name in order by in ASP, however I am not able to find anything in Spring or JPA.
"Order By" using a parameter for the column name
http://databases.aspfaq.com/database/how-do-i-use-a-variable-in-an-order-by-clause.html

Passing List<Integer> in spring data jpa native query

Using spring data JPA, I am trying to make this sort of query (it is more complex, this is a simple case)
#Query(nativeQuery = true,
value = "SELECT * FROM events WHERE typeId IN (?1)")
List<Event> findEventsByType(List<Integer> types);
When I launch the query, an exception raises:
org.postgresql.util.PSQLException: Can't infer the SQL type to use for an instance of java.util.ArrayList. Use setObject() with an explicit Types value to specify the type to use.
I have tried List < Integer >, Integer[], Object[] and String but it is not working...
Can't I pass list of values?
Which is the best approach to make this sort of queries?
Thanks!
Try taking away the #Query and make the method name:
public List<Event> findByTypeIn(List<Integer> types);
See table 2.2 in the link: http://docs.spring.io/spring-data/jpa/docs/1.2.0.RELEASE/reference/html/
I tried like below and it works for me.
#Query(value = "select * from events where type_id in :types", nativeQuery = true)
List<Event> findEventsByType(#Param("types") List<Integer> types);
#Query(value = "SELECT c from Company c where " +
"c.companyName IN (:company_names)")
List<Company> findCompaniesByName(#Param("company_names") List<String> companyNames);
This is the solution to your problem.
Here I am passing List which contains company names and I am querying DB and storing result in List.
Hope this hepls!
Use JPQL. A native query is or should be passed to the database exactly as you have created the SQL string, and unless your driver can take a serialized collection and understand that the single parameter needs to be interpreted as many, it just won't work. The collection you pass in needs the SQL expanded from (?) to (?, ?,...) based on the number of elements in a collection, and JDBC drivers just are not able to do this, and JPA providers are required to execute the string as is.
A JPQL query allows the JPA provider to create the SQL it needs dynamically based on the list passed in, so it can expand the collection for you.
Try this. It will work for Native Query in SpringBoot JPA:
#Query(value = "SELECT * FROM table WHERE columnName IN (:inputList)" ,
nativeQuery = true)
List<Object> findByObjectList(#Param("inputList") List<Object> inputList);
And also in case of JPA, try the below :
List<Object> findByObjectList(List<Object> inputList)
I know this is a little bit out of context (we use Update and not Select), but this can be usefull for others :
/**
* Update the state of list of entities using their ids
* #param ids request ids
* #param state new state
* #return
*/
#Modifying
#Query(value = "UPDATE AbstractRequest SET state = :state WHERE id IN (:ids)")
int updateStates(#Param("ids") List<Long> ids, #Param("state") InternalRequestStep state);
pass array this way inside IN Clause
#Query(value = "select name from teams where name in :names", nativeQuery = true)
List<String> getNames(#Param("names") String[] names);
Call this way
String[] names = {"testing team","development team"};
List<String> teamtest = teamRepository.getNames(names);
Remove brackets around (?1) parameter. Your query value should look like that:
#Query(value = "SELECT * FROM events WHERE typeId IN ?1")
try querying like this:
#Query(nativeQuery = true,
value = "SELECT * FROM events WHERE typeId = ?1")
List<Event> findEventsByType(List<Integer> types);
did it work?

Porting query from JPQL to mongo using spring data mongo Criteria

I've ported some of my Entity from JPA to document and now porting some of my queries.
here is the JPA query:
em.createQuery("select distinct c from CustomerImpl c left join fetch c.addresses ca where (:name is null or c.firstName LIKE :name or c.lastName LIKE :name) and (:ref is null or c.externalReference LIKE :ref) and (:city is null or ca.city LIKE :city) order by c.firstName").setParameter("name", name).setParameter("ref", customerRef).setParameter("city", city).getResultList();
below is my attempt :
Criteria orNameCriteria = new Criteria().orOperator(Criteria.where("firstName").is(null), Criteria.where("firstName").is(name), Criteria.where("lastName").is(name));
Criteria orCustomerRefCriteria = new Criteria().orOperator(Criteria.where("externalReference").is(null), Criteria.where("externalReference").regex(customerRef,"i"));
Criteria orAddress = new Criteria().orOperator(Criteria.where("addresses.city").is(null), Criteria.where("addresses.city").regex(city, "i"));
Query nameq = new Query(new Criteria().andOperator(orNameCriteria,orCustomerRefCriteria,orAddress));
this query return zero size arraylist. I've then changed the orNameCriteria to use is clause and making sure the data contained in name variable has / as suffix and prefix. That didn't work as well.
but queries from mongoVue and RockMongo clients :
{ firstName: /SAM/}
returns data.
Question 1: How do you write LIKE CLAUSE with spring-data-mongo Criteria?
Question 2 : is that the right way to use or and and clause with criteria
Thanks for reading
Criteria.where("field").regex(pattern) should work
Since I don't have the ability add comments...
If you do a static import on Criteria, it will make your where clauses look a lot better.
Criteria orAddress = new Criteria().orOperator(where("addresses.city").is(null), where("addresses.city").regex(city, "i"));