Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement pagination in NestJS with TypeORM

Is there any way to get the total count and records with a single query, instead of running it as 2 separate queries?

If it's not possible, is there any way to reuse the where condition in both queries?

async findAll(query): Promise<Paginate> {   const take = query.take || 10   const skip = query.skip || 0   const keyword = query.keyword || ''    const builder = this.userRepository.createQueryBuilder("user")   const total = await builder.where("user.name like :name", { name: '%' + keyword + '%' }).getCount()   const data = await builder.where("user.name like :name", { name: '%' + keyword + '%' }).orderBy('name', 'DESC').skip(skip).take(take).getMany();    return {     data: data,     count: total   } }  {   count: 10,   data: [     {       id: 1,       name: 'David'     },     {       id: 2,       name: 'Alex'     }] } 
like image 590
HanJeaHwan Avatar asked Dec 25 '18 12:12

HanJeaHwan


People also ask

What is ORM in NestJS?

ORMs in NestJS Object-relational mapping (ORM) is a technique that abstracts your database tables to data objects in memory. It allows you to query and write data to databases using data objects. ORMs are used to make database access easier, as developers won't need to write raw queries.

What is pagination used for?

Pagination is the process of separating print or digital content into discrete pages. For print documents and some online content, pagination also refers to the automated process of adding consecutive numbers to identify the sequential order of pages.


2 Answers

You can find some nice example in this project. In short typeorm has a really nice method specific to this usecase findAndCount.

async findAll(query): Promise<Paginate> {     const take = query.take || 10     const skip = query.skip || 0     const keyword = query.keyword || ''      const [result, total] = await this.userRepository.findAndCount(         {             where: { name: Like('%' + keyword + '%') }, order: { name: "DESC" },             take: take,             skip: skip         }     );      return {         data: result,         count: total     } } 

Repository API you can find here. More documentation about Repository class can be found here.

like image 93
Ivan Vasiljevic Avatar answered Sep 20 '22 13:09

Ivan Vasiljevic


summing up...

This middleware checks if you have the take and skip parameters in the URL, if it does, it converts from string to number, if you don't use the default values. 10 for take and 0 for skip.

take is the number of results per page and skip, from where it should start reading records.

With that, I set up to intercept the "product / paged" route just for the GET method.

With this I can retrieve these values in the controller and pass to TypeORM or an SQL query.

Folders

@Injectable() export class PagerMiddleware implements NestMiddleware {   use(req: any, res: any, next: () => void) {     req.query.take = +req.query.take || 10;     req.query.skip = +req.query.skip || 0;     next();   } } 

and apply in module.

export class AdminFeatureApi implements NestModule {   configure(consumer: MiddlewareConsumer) {     consumer.apply(PagerMiddleware)     .forRoutes({ path: 'product/paged', method: RequestMethod.GET })   } } 

Controller

@Controller('product') export class TrainingDomainController {   constructor(private service: YourService) {}    @Get('paged')   get(@Query() { take, skip }) {     return this.service.findAll(take, skip);   } } 

and service

@Injectable() export class YourService {   constructor(     @InjectRepository(YourEntity)     private readonly repo: MongoRepository<YourEntity>   ) {}    async findAll(take: number = 10, skip: number = 0) {     const [data, total] = await this.repo.findAndCount({ take, skip });     return { data, total };   } } 

ok?

like image 26
Gui Seek Avatar answered Sep 19 '22 13:09

Gui Seek