101

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!

rakpan
  • 2,773
  • 4
  • 26
  • 36
  • 12
    Add multiple `sort` attributes. `sort=name,asc&sort=numberOfHands,desc`. – M. Deinum Oct 08 '15 at 14:14
  • Great! that works.. But that is weird.. Except for a string being appended to URL, I'm not sure if there is a direct way of generating such URL through JavaScript.. Please let me know if I'm wrong.. – rakpan Oct 09 '15 at 03:01
  • 1
    Why would it be weird that is just the way the web (or URLs) work. You can generate whatever URL you like with javascript. See http://stackoverflow.com/questions/24059773/correct-way-to-pass-multiple-values-for-same-parameter-name-in-get-request. – M. Deinum Oct 09 '15 at 05:47
  • 2
    @M.Deinum - You might wanna turn this into an answer as it's correct. If you have trouble creating such URIs via JavaScript, blame JavaScript or the library you're using. :) – Oliver Drotbohm Oct 09 '15 at 08:43

3 Answers3

143

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[].

Community
  • 1
  • 1
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
64

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)

BitfulByte
  • 4,117
  • 1
  • 30
  • 40
  • 1
    Interesting, though I guess this will only work on the server side. – aboger Dec 25 '18 at 20:09
  • Yes, this works when you need to "hardcode" it server side. It uses the [Sort](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Sort.html) class from Spring data. I have clarified the answer so it's hopefully more clear now :-) – BitfulByte Dec 27 '18 at 07:33
  • Say I use JPQL and join across multiple tables. And I want to sort it based on two columns. One from the first table and another from second table. if I pass it as `Sort.by(Sort.Direction.ASC,"first_table_col","second_table_col")` , I get an exception saying "second_table_col" not found in First_table. Is it possible ? – padmanabhanm Jun 10 '19 at 13:30
  • @iamL perhaps try with the prefix of the second table? – BitfulByte Jun 11 '19 at 07:33
  • 1
    @PimHazebroek .. That is what I ended up doing. Cleared alias names for the tables and it worked. Thanks. – padmanabhanm Jun 12 '19 at 08:56
  • 1
    Second way to construct multi sort in repository: `return this.bookRepository.findAll(Sort.by("published").descending().and(Sort.by("title")).a cending());` – Seldo97 Jul 25 '20 at 22:08
0

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)));