spring-data-jpa-sort-order-by-multiple-columns-feature-image

Spring Data JPA Sort/Order by multiple Columns | Spring Boot

In previous tutorial, we’ve known how to build Spring Boot Rest CRUD Apis with Spring Data JPA. Today I will show you how to sort/order result by multiple Columns in Spring Boot with Spring Data JPA. You also know way to apply sorting and paging together.

Related Posts:
Spring Boot, Spring Data JPA – Rest CRUD API example
Spring Boot Pagination & Filter example | Spring JPA, Pageable
Spring Boot @ControllerAdvice & @ExceptionHandler example

More Practice:
Spring Boot Token based Authentication with Spring Security & JWT


Spring Data Sort multiple Columns example Overview

Assume that we have tutorials table in database like this:

spring-data-jpa-sort-order-by-multiple-columns-example-table

Here are some url samples for order by single/multiple Columns (with/without paging), sort by Ascending or Descending:

  • /api/tutorials
    sort by [id, descending] (default)
  • /api/tutorials?sort=title,asc
    sort by [title, ascending]
  • /api/tutorials?sort=published,desc&sort=title,asc
    order by column [published, descending], then order by column [title, ascending]
  • /api/tutorials?page=0&size=3&sort=published,desc&sort=title,asc
    order by column [published, descending], then order by column [title, ascending] together with pagination

In this tutorial, to help you have a clear idea in Sorting using Spring Boot, I will create separated endpoints with different response structure:

  • for Sorting by Multiple Columns: /api/sortedtutorials
  • [
        {
            "id": 8,
            "title": "Spring Data JPA Tut#8",
            "description": "Tut#8 Description",
            "published": true
        },
        ...
        ...
        ...
        {
            "id": 1,
            "title": "Spring Boot Tut#1",
            "description": "Tut#1 Description",
            "published": false
        }
    ]
    
  • for Paging & Sorting coming together: /api/tutorials
  • {
        "totalItems": 8,
        "tutorials": [
            ...
        ],
        "totalPages": 3,
        "currentPage": 1
    }
    

    Please visit: Spring Boot Pagination and Sorting example

Let’s look at the result after building this Spring Boot Application:

– Get all Tutorials with default order [id, descending]:

spring-data-jpa-sort-order-by-multiple-columns-example-default-order

– Get all Tutorials, sort by single column [title, ascending]:

spring-data-jpa-sort-order-by-multiple-columns-example-single-column

– Get all Tutorials, sort by multiple columns [published, descending] & [title, ascending]:

spring-data-jpa-sort-order-by-multiple-columns-example-without-paging

Order by multiple Columns with Spring Data JPA

To help us deal with this situation, Spring Data JPA provides way to implement pagination with PagingAndSortingRepository.

PagingAndSortingRepository extends CrudRepository to provide additional methods to retrieve entities using the sorting abstraction. So you can add a special Sort parameter to your query method.

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
  Iterable<T> findAll(Sort sort);
}

findAll(Sort sort): returns a Iterable of entities meeting the sorting condition provided by Sort object.

You can also define more derived and custom query methods with additional Sort parameter. For example, the following method returns List of Tutorials which title contains a given string:

List<Tutorial> findByTitleContaining(String title, Sort sort);

You can find more supported keywords inside method names here.

Let’s continue to explore Sort class.

Spring Data Sort and Order

The Sort class provides sorting options for database queries with more flexibility in choosing single/multiple sort columns and directions (ascending/descending).

For example, we use by(), descending(), and() methods to create Sort object and pass it to Repository.findAll():

// order by 'published' column - ascending
List<Tutorial> tutorials =
     tutorialRepository.findAll(Sort.by("published"));

// order by 'published' column, descending
List<Tutorial> tutorials =
     tutorialRepository.findAll(Sort.by("published").descending());

// order by 'published' column - descending, then order by 'title' - ascending
List<Tutorial> tutorials =
     tutorialRepository.findAll(Sort.by("published").descending().and(Sort.by("title")));

We can also create a new Sort object with List of Order objects.

List<Order> orders = new ArrayList<Order>();

Order order1 = new Order(Sort.Direction.DESC, "published");
orders.add(order1);

Order order2 = new Order(Sort.Direction.ASC, "title");
orders.add(order2);

List<Tutorial> tutorials = tutorialRepository.findAll(Sort.by(orders));

Paging and Sorting

What if we want todo both sorting and paging the data?

CrudRepository also provides additional methods to retrieve entities using the pagination abstraction.

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
  Page<T> findAll(Pageable pageable);
}

findAll(Pageable pageable): returns a Page of entities meeting the paging condition provided by Pageable object.

Spring Data also supports many useful Query Creation from method names that we’re gonna use to filter result in this example such as:

Page<Tutorial> findByPublished(boolean published, Pageable pageable);
Page<Tutorial> findByTitleContaining(String title, Pageable pageable);


For more details about Pagination and Sorting, please visit:
Spring Boot Pagination and Sorting example

Spring Boot Application

You can follow step by step, or get source code in this post:
Spring Boot, Spring Data JPA – Rest CRUD API example

The Spring Project contains structure that we only need to add some changes to make the pagination work well.

spring-boot-data-jpa-crud-example-project-structure

Or you can get the new Github source code (including paging and sorting) at the end of this tutorial.

Data Model

This is the Tutorial entity that we’re gonna work:

model/Tutorial.java

package com.bezkoder.spring.data.jpa.pagingsorting.model;

import javax.persistence.*;

@Entity
@Table(name = "tutorials")
public class Tutorial {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  @Column(name = "title")
  private String title;

  @Column(name = "description")
  private String description;

  @Column(name = "published")
  private boolean published;

  public Tutorial() {

  }

  public Tutorial(String title, String description, boolean published) {
    this.title = title;
    this.description = description;
    this.published = published;
  }

  public long getId() {
    return id;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public boolean isPublished() {
    return published;
  }

  public void setPublished(boolean isPublished) {
    this.published = isPublished;
  }

  @Override
  public String toString() {
    return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
  }
}

Repository that supports Paging and Sorting

Early in this tutorial, we know PagingAndSortingRepository, but in this example, for keeping the continuity and taking advantage Spring Data JPA, we continue to use JpaRepository which extends PagingAndSortingRepository interface.

repository/TutorialRepository.java

package com.bezkoder.spring.data.jpa.pagingsorting.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;

import com.bezkoder.spring.data.jpa.pagingsorting.model.Tutorial;

public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
  Page<Tutorial> findByPublished(boolean published, Pageable pageable);

  Page<Tutorial> findByTitleContaining(String title, Pageable pageable);
  
  List<Tutorial> findByTitleContaining(String title, Sort sort);
}

In the code above, we use add pageable parameter with Spring Query Creation to find all Tutorials which title containing input string.

Controller with Sort/Order By Multiple Columns

To get multiple sort request parameters, we use @RequestParam String[] sort with defaultValue = "id,desc".

Before writing the Controller method to handle the case, let’s see what we retrieve with the parameters:

  • ?sort=column1,direction1: sorting single column
    String[] sort is an array with 2 elements: [“column1”, “direction1”]
  • ?sort=column1,direction1&sort=column2,direction2: sorting multiple columns
    String[] sort is also an array with 2 elements: [“column1, direction1”, “column2, direction2”]

That’s why we need to check if the first item in the array contains "," or not.

We also need to convert "asc"/"desc" into Sort.Direction.ASC/Sort.Direction.DES for working with Sort.Order class.

controller/TutorialController.java

package com.bezkoder.spring.data.jpa.pagingsorting.controller;

import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
...
import com.bezkoder.spring.data.jpa.pagingsorting.model.Tutorial;
import com.bezkoder.spring.data.jpa.pagingsorting.repository.TutorialRepository;

@RestController
@RequestMapping("/api")
public class TutorialController {

  @Autowired
  TutorialRepository tutorialRepository;

  private Sort.Direction getSortDirection(String direction) {
    if (direction.equals("asc")) {
      return Sort.Direction.ASC;
    } else if (direction.equals("desc")) {
      return Sort.Direction.DESC;
    }

    return Sort.Direction.ASC;
  }

  @GetMapping("/sortedtutorials")
  public ResponseEntity<List<Tutorial>> getAllTutorials(@RequestParam(defaultValue = "id,desc") String[] sort) {

    try {
      List<Order> orders = new ArrayList<Order>();

      if (sort[0].contains(",")) {
        // will sort more than 2 columns
        for (String sortOrder : sort) {
          // sortOrder="column, direction"
          String[] _sort = sortOrder.split(",");
          orders.add(new Order(getSortDirection(_sort[1]), _sort[0]));
        }
      } else {
        // sort=[column, direction]
        orders.add(new Order(getSortDirection(sort[1]), sort[0]));
      }

      List<Tutorial> tutorials = tutorialRepository.findAll(Sort.by(orders));

      if (tutorials.isEmpty()) {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
      }

      return new ResponseEntity<>(tutorials, HttpStatus.OK);
    } catch (Exception e) {
      return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

}

How about controller that brings pagination and sorting together?
Please visit: Spring Boot Pagination and Sorting example

Conclusion

In this post, we have learned how to sort/order by multiple columns in Spring Boot application using Spring Data JPA, Sort class and Pageable interface.

We also see that JpaRepository supports a great way to make sorting, paging and filter methods without need of boilerplate code.

You can also know how to:
– paging and filter in this article.
– handle exception in this post.
– deploy this Spring Boot App on AWS (for free) with this tutorial.

Happy learning! See you again.

Further Reading

For pagination and sorting together:
Spring Boot Pagination and Sorting example

Source Code

You can find the complete source code for this tutorial on Github.

2 thoughts to “Spring Data JPA Sort/Order by multiple Columns | Spring Boot”

Leave a Reply

Your email address will not be published. Required fields are marked *