SpringBoot MongoDB Pagination RestAPIs Example

Spring Boot MongoDB Pagination and Sorting Example

Tutorial: SpringBoot MongoDB Pagination RestAPIs Example with MongoRepository (extends PagingAndSortingRepository)

When we have a large dataset and we want to present it to the user in smaller chunks, pagination and sorting is often helpful solution. So in the tutorial, I introduce how to build “SpringBoot MongoDB Pagination RestAPIs Example” use Spring MongoRepository APIs that extends PagingAndSortingRepository to do the task with SpringBoot project example.

Here is a to do list for the tutorial:

– Introduce overview SpringBoot and MongoDB database project.
– Explain a hierarchy diagram of MongoRepository and PagingAndSortingRepository.
– Guide step by step with clearly and running coding examples for how to create a SpringBoot MongoDB Pagination RestAPIs.
– Create an integrative testsuite pagination sorting and filtering requests from Postman client to MongoDB Atlas through SpringBoot Pagination RestAPIs.

Related posts:


Goal – Spring Boot Pagination and Sorting with MongoDB Example

We create a ‘SpringBoot MongoDB Pagination and Sorting Example’ project as below struture:

SpringBoot MongoDB Pagination Project Structure
SpringBoot MongoDB Pagination Project Structure

– Paging Request:

SpringBoot MongoDB make a pagination request 1
SpringBoot MongoDB make a pagination request 1

– Pagination and Sorting request:

SpringBoot MongoDB make a pagination request 7
SpringBoot MongoDB make a pagination request 7

PagingAndSorting Repository

PagingAndSortingRepository is an extension of CrudRepository to provide additional methods to retrieve entities using the pagination and sorting abstraction. Here is the sourcecode of it:


@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
	Iterable<T> findAll(Sort sort);
	Page<T> findAll(Pageable pageable);
}
  • findAll(Sort sort) returns all entities sorted by the given options.
  • findAll(Pageable pageable) Returns a page of entities meeting the paging restriction provided in the Pageable object.

Here is the hierarchy of PagingAndSortingRepository :

PagingAndSortingRepository hierarchy - MongoRepository
PagingAndSortingRepository hierarchy – MongoRepository

So MongoRepository of Spring MongoDB is an alternative solution for PagingAndSortingRepository:

@NoRepositoryBean
public interface MongoRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

Spring MongoDB Pagination

With the tutorial “Spring Boot MongoDB Pagination and Sorting Example” we use Spring data’s methods:
Page<T> findAll(Pageable pageable);

It returns a Page of entities meeting the paging restriction provided in the Pageable object.

– Here is how the Page interface is defined:

Spring Data Page Interface
Spring Data Page Interface

– Here is how to Pageable interface is defined:

Spring data Pagable Interface for pagination filtering and sorting
Spring data Pagable Interface for pagination filtering and sorting

Examples coding:


@Autowired
CustomerRepository customerRepository;

@GetMapping("/pageable")
public Page<Customer> retrieveCustomerWithPaging(@Param(value = "page") int page, 
											@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Page<Customer> customers  = customerRepository.findAll(requestedPage);
	return customers;
}

We use the PageRequest to construct a Pageable object then pass it to the findAll() method of PagingAndSortingRepository.


public class PageRequest extends AbstractPageRequest {
	private final Sort sort;

	protected PageRequest(int page, int size, Sort sort) {}

	public static PageRequest of(int page, int size) {
		return of(page, size, Sort.unsorted());
	}

	public static PageRequest of(int page, int size, Sort sort) {}

	public static PageRequest of(int page, int size, Direction direction, String... properties) {}

	public Sort getSort() {}

	@Override
	public Pageable next() {}
	
	@Override
	public PageRequest previous() {}

	@Override
	public Pageable first() {}
}

We can also do a pagination with the findAll method included a condition:

@GetMapping("/pageablebysalary")
public Slice<Customer> retrieveCustomerBySalaryWithPaging(@Param(value = "salary") double salary,
															@Param(value = "page") int page, 
															@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Slice<Customer> customers  = customerRepository.findAllBySalary(salary, requestedPage);
	return customers;
}

We can return a Page object to client or an alternative solution likes Slice or a list objects. We also can return a custom class object to client with just needed properties:

Class org.springframework.data.domain.Slice<T>

	Methods:	
		org.springframework.data.domain.Slice.getNumber()
		org.springframework.data.domain.Slice.getSize()
		org.springframework.data.domain.Slice.getNumberOfElements()
		org.springframework.data.domain.Slice.getContent()
		org.springframework.data.domain.Slice.hasContent()
		org.springframework.data.domain.Slice.getSort()
		org.springframework.data.domain.Slice.isFirst()
		org.springframework.data.domain.Slice.isLast()
		org.springframework.data.domain.Slice.hasNext()
		org.springframework.data.domain.Slice.hasPrevious()
		org.springframework.data.domain.Slice.getPageable()
		org.springframework.data.domain.Slice.nextPageable()
		org.springframework.data.domain.Slice.previousPageable()
		org.springframework.data.domain.Slice.map(Function<? super T, ? extends U>)
		org.springframework.data.domain.Slice.nextOrLastPageable()
		org.springframework.data.domain.Slice.previousOrFirstPageable()

1. create a custom Response object from a returned Page object:


Pageable requestedPage = PageRequest.of(page, size);
Page<Customer> customers  = customerRepository.findAll(requestedPage);
Response res = new Response(customers.getContent(), customers.getTotalPages(),
								customers.getNumber(), customers.getSize());

2. return just a list of customers to client:


Pageable requestedPage = PageRequest.of(page, size);
Page<Customer> customers  = customerRepository.findAll(requestedPage);
return customers.toList();

3. return a Slice object:


Pageable requestedPage = PageRequest.of(page, size);
Slice<Customer> customers  = customerRepository.findAllBySalary(salary, requestedPage);

A Page<T> instance, in addition to having the list of Customer, also knows about the total number of available pages. It triggers an additional count query to achieve it. To avoid such an overhead cost, we can instead return a Slice<T> or a List<T>.

A Slice only knows about whether the next slice is available or not.

How to use Spring Boot Pagination with Filtering with MongoDB?

For filtering data with pagination, Spring Data provides many useful Query Creation from method names:


Slice findAllBySalary (double salary, Pageable pageable);
Page findAllByAgeGreaterThan(int age, Pageable pageable);
  • GreaterThan examples findAllByAgeGreaterThan(int age, Pageable pageable); means … where x.age> ?1
  • Is, Equals examples findAllBySalary (double salary, Pageable pageable) means … where x.salary = ?1

You can findout more about the supporting keywords for searching with Spring Data, go to the refference link: here

Paging and Sorting

For sorting with Spring Data, we use the function: Iterable<T> findAll(Sort sort);.

We can use public static methods by() to build the Sort objects:

  • public static Sort by(String... properties) creates a new Sort for the given properties.
  • public static Sort by(List≶Order> orders) creates a new Sort for the given list Orders
  • public static Sort by(Order... orders) create a new Sort for the given Orders
  • public static Sort by(Direction direction, String... properties)

If we want to both sort and page our data, We can do that by passing the sorting details into our PageRequest object itself:

Pageable sortedBySalary = 
  PageRequest.of(0, 3, Sort.by("salary"));
 
Pageable sortedBySalaryDesc = 
  PageRequest.of(0, 3, Sort.by("salary").descending());
 
Pageable sortedBySalaryDescAgeAndFirstnameAsc = 
  PageRequest.of(0, 5, Sort.by("salary").descending().and(Sort.by("age")).and(Sort.by("firstname")));

How to implement a Pagination Filtering and Sorting function with Spring MongoDB Data?

To do the pagination and sorting and filering combination, we can use the Sort object combining with keyword Query Creation, examples:


Pageable requestedPage = PageRequest.of(page, size, Sort.by("salary")
														.descending()
														.and(Sort.by("age"))
														.and(Sort.by("firstname")));

Page<Customer> customers  = customerRepository.findAllByAgeGreaterThan(age, requestedPage);

Development – How to code it?

Create a SpringBoot project

We create a SpringBoot project with 3 dependencies:

  • Spring Data MongoDB
  • Spring Web
  • MySQL driver or PostgreSQL driver

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Create Spring MongoDB Document Model

We create a Customer document model class with 7 fields: id, firstname, lastname, address, age, salary, copyrightBy.

SpringBoot data model
SpringBoot data model
package com.loizenjava.springboot.pagination.mongodb.document;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Document(collection = "customers")
public class Customer {
	@Id
	private String id;
	private String firstname;
	private String lastname;
	private Integer age;
	private String address;
	private int salary;
	
	@Field
	private String copyrightby = "https://loizenjava.com";

	public Customer(String firstname, String lastname, String address, int age, int salary) {
		this.firstname = firstname;
		this.lastname = lastname;
		this.age = age;
		this.address = address;
		this.salary = salary;
	}
	
	public void setId(String id) {
		this.id = id;
	}
	
	public String getId() {
		return this.id;
	}
	
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	
	public String getFirstname() {
		return this.firstname;
	}
	
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
	
	public String getLastname() {
		return this.lastname;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	public int getAge() {
		return this.age;
	}
	
	public void setAddress(String address) {
		this.address = address;
	}
	
	public String getAddress() {
		return this.address;
	}
	
	public void setSalary(int salary) {
		this.salary = salary;
	}
	
	public int getSalary() {
		return this.salary;
	}
	
	public void setCopyrightby(String copyrightby) {
		this.copyrightby = copyrightby;
	}
	
	public String getCopyrightby() {
		return this.copyrightby;
	}
}

@Document identifies a domain object to be persisted to MongoDB.
org.springframework.data.annotation.Id demarcates an identifier.
@Field – Annotation to define custom metadata for document fields.

Database Configuration

Configuration database in application.properties file:

#mongodb
spring.data.mongodb.uri=mongodb+srv://loizenjava:12345@cluster0.uhqpv.mongodb.net/loizenjavadb?retryWrites=true&w=majority

Implement SpringBoot CustomerRepository interface

Create interface CustomerRepository extends PagingAndSortingRepository:

package com.loizenjava.springboot.pagingansorting.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import com.loizenjava.springboot.pagination.mongodb.document.Customer;

@Repository
public interface CustomerRepository extends MongoRepository<Customer, String>{	
	Slice<Customer> findAllBySalary (double salary, Pageable pageable);
	Page<Customer> findAllByAgeGreaterThan(int age, Pageable pageable);
}

Implement SpringBoot RestAPIs Controller

– Create a RestController class:

@org.springframework.web.bind.annotation.RestController
@RequestMapping("/api/customers")
@CrossOrigin(origins = "http://localhost:4200")
public class RestController {
        @Autowired
	CustomerRepository customerRepository;
...
}

SpringBoot RestAPIs for Requesting Customer List with Pagination

We define 3 SpringBoot APIs:

  • Url API /api/customers/pageable returns a Page object
  • Url API /api/customers/pageable/list returns a List of Customer object
  • Url API /api/customers/custom/pageable returns a custom user-defined Response object
@GetMapping("/pageable")
public Page<Customer> retrieveCustomerWithPaging(@Param(value = "page") int page, 
											@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Page<Customer> customers  = customerRepository.findAll(requestedPage);
	return customers;
}

@GetMapping("/custom/pageable")
public Response retrieveCustomer(@Param(value = "page") int page, 
											@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Page<Customer> customers  = customerRepository.findAll(requestedPage);
	Response res = new Response(customers.getContent(), customers.getTotalPages(),
									customers.getNumber(), customers.getSize());
	
	return res;
}

@GetMapping("/pageable/list")
public List<Customer> retrieveCustomerListWithPaging(@Param(value = "page") int page, 
												@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Page<Customer> customers  = customerRepository.findAll(requestedPage);
	return customers.toList();
}

RestAPIs for Customer Pagination with Paging and Filtering

We define 2 URLs for filtering and paging:

  • /api/customers/pageablebysalary is used to retrieve a Customer page with a salary criteria for filtering
  • /api/customers/pageable/byagegreaterthan is used to retrieve a Customer page with a age criteria for filtering
@GetMapping("/pageablebysalary")
public Slice<Customer> retrieveCustomerBySalaryWithPaging(@Param(value = "salary") double salary,
															@Param(value = "page") int page, 
															@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Slice<Customer> customers  = customerRepository.findAllBySalary(salary, requestedPage);
	return customers;
}

@GetMapping("/pageable/byagegreaterthan")
public Slice<Customer> retrieveCustomerByAgeGreaterThan(@Param(value = "age") int age,
															@Param(value = "page") int page, 
															@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size);
	Page<Customer> customers  = customerRepository.findAllByAgeGreaterThan(age, requestedPage);
	return customers;
}

RestAPIs to retrieve Customer List with Pagination and Sorting

We implement a Url API /api/customers/pagingandsorting for getting a customer list with pagination and sorting:


@GetMapping("/pagingandsorting")
public Page<Customer> pagingAndSortingCustomers(@Param(value = "page") int page, 
											@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size, Sort.by("salary")
															.descending()
															.and(Sort.by("age"))
															.and(Sort.by("firstname")));
	Page<Customer> customers  = customerRepository.findAll(requestedPage);
	return customers;		
}

SpringBoot RestAPIs to Pagination Filtering and Sorting

We implement a RestAPIs at URL /api/customers/pagingfilteringandsorting to retrive Customer page with a age criteria for filtering and also using age field and firstname field for sorting.

@GetMapping("/pagingfilteringandsorting")
public Page<Customer> pagingFilteringAndSortingCustomersByAge(@Param(value = "salary") int age@Param(value = "age") int age, 
						                                    @Param(value = "page") int page, 
															@Param(value = "size") int size){
	Pageable requestedPage = PageRequest.of(page, size, Sort.by("salary")
															.descending()
															.and(Sort.by("age"))
															.and(Sort.by("firstname")));
	
	Page<Customer> customers  = customerRepository.findAllByAgeGreaterThan(age, requestedPage);
	return customers;		
}

Testing – Spring Boot Pagination and Sorting Example

Below is a suite of testcases for “Spring Boot Pagination and Sorting Example” project:

Testcase 1 – SpringBoot MongoDB Pagination request

– Request 1 at URL http://localhost:8080/api/customers/pageable?page=0&size=5
Return a Page object

SpringBoot MongoDB make a pagination request 1
SpringBoot MongoDB make a pagination request 1

– Request 2 at URL http://localhost:8080/api/customers/pageable/list?page=0&size=5
Just return a List of Customer

SpringBoot MongoDB make a pagination request 2
SpringBoot MongoDB make a pagination request 2

– Request 3 at URL http://localhost:8080/api/customers/custom/pageable?page=0&size=5
Return a custom user-defined Response object

SpringBoot MongoDB make a pagination request 3
SpringBoot MongoDB make a pagination request 3

Testcase 2 – SpringBoot MongoDB Pagination and Filtering RestAPIs

– Request 1 at URL http://localhost:8080/api/customers/pageablebysalary?salary=4000&page=0&size=5
Do a pagination with salary=4000 condition for paging

SpringBoot MongoDB make a pagination request 4
SpringBoot MongoDB make a pagination request 4

– Request 2 at URL http://localhost:8080/api/customers/pageable/byagegreaterthan?age=40&page=0&size=5
Do a pagination and filtering with age > 40:

SpringBoot MongoDB make a pagination request 5
SpringBoot MongoDB make a pagination request 5

Testcase 3 – SpringBoot MongoDB Paging and Sorting request

– Request at URL for Paging and sorting:
http://localhost:8080/api/customers/pagingandsorting?page=0&size=5

SpringBoot MongoDB make a pagination request 6
SpringBoot MongoDB make a pagination request 6

Testcase 4 – SpringBoot MongoDB Pagination, Filtering and Sorting request

– Request at URL for Paging and sorting:
http://localhost:8080/api/customers/pagingfilteringandsorting?salary=3000&age=25&page=0&size=5

SpringBoot MongoDB make a pagination request 7
SpringBoot MongoDB make a pagination request 7

Bootstrap View

We use Bootstrap framework to develop a view for the tutorial “Spring Boot Pagination and Sorting Example”:

Bootstrap View with pagination and sorting example
Bootstrap View with pagination and sorting example

Sourcecode

Below is a clearly & running sourcecode for “Spring Boot Pagination and Sorting Example”:

SpringBootPaginationMongoDB

– Github Sourcecode for SpringBoot MongoDB Pagination and Sorting Example:

Github – SpringBoot MongoDB Pagination

Further Reading for SpringBoot MongoDB Pagination and Sorting Example

Related posts:


Leave a Reply

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