nestjs-typeorm-paginate vs nestjs-paginate
Pagination Libraries for NestJS Comparison
1 Year
nestjs-typeorm-paginatenestjs-paginate
What's Pagination Libraries for NestJS?

Pagination libraries in NestJS are essential tools that help developers manage large datasets by breaking them into smaller, more manageable chunks. These libraries streamline the process of implementing pagination in applications, allowing for efficient data retrieval and improved user experience. They provide built-in methods to handle pagination logic, making it easier to integrate with various data sources, including databases and APIs. By using these libraries, developers can enhance performance and usability in applications that deal with extensive data sets.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
nestjs-typeorm-paginate70,83385635 kB302 years agoMIT
nestjs-paginate21,730493608 kB667 days agoMIT
Feature Comparison: nestjs-typeorm-paginate vs nestjs-paginate

Integration

  • nestjs-typeorm-paginate:

    This package is specifically designed for TypeORM, providing seamless integration with TypeORM's query builder. It allows developers to leverage TypeORM's features while implementing pagination, ensuring optimized performance and ease of use.

  • nestjs-paginate:

    This package offers a generic pagination solution that can be integrated with any data source, making it versatile for various applications. It allows developers to implement pagination logic without being tied to a specific ORM or database technology.

Customization

  • nestjs-typeorm-paginate:

    While 'nestjs-typeorm-paginate' also offers customization, it is more focused on TypeORM-specific features. Developers can customize pagination behavior using TypeORM's query builder, but the options may be limited compared to the more generic 'nestjs-paginate'.

  • nestjs-paginate:

    'nestjs-paginate' allows for extensive customization options, enabling developers to define pagination parameters such as page size, sorting, and filtering according to their application needs. This flexibility makes it suitable for diverse use cases.

Performance

  • nestjs-typeorm-paginate:

    Being built for TypeORM, this package takes advantage of TypeORM's optimization features, ensuring that pagination queries are executed efficiently. It can handle complex queries while maintaining performance, especially for large datasets.

  • nestjs-paginate:

    This package is optimized for performance, allowing developers to implement efficient pagination without significant overhead. It minimizes the amount of data processed at once, which can lead to faster response times in applications.

Learning Curve

  • nestjs-typeorm-paginate:

    The learning curve for 'nestjs-typeorm-paginate' may be steeper for those unfamiliar with TypeORM. However, for developers already experienced with TypeORM, it offers a familiar approach to pagination, making it easier to adopt.

  • nestjs-paginate:

    The learning curve for 'nestjs-paginate' is relatively low, as it provides straightforward methods for implementing pagination without requiring deep knowledge of any specific ORM. Developers can quickly grasp its usage and integrate it into their projects.

Community Support

  • nestjs-typeorm-paginate:

    As a TypeORM-specific package, it benefits from the established TypeORM community. Developers can find resources and support related to both TypeORM and pagination, making it easier to troubleshoot and implement.

  • nestjs-paginate:

    This package has a growing community and documentation, which can be helpful for developers seeking support or examples. Its flexibility allows it to be used in various projects, contributing to its community growth.

How to Choose: nestjs-typeorm-paginate vs nestjs-paginate
  • nestjs-typeorm-paginate:

    Choose 'nestjs-typeorm-paginate' if you are using TypeORM as your ORM and want a pagination solution that is specifically designed to work seamlessly with TypeORM's query builder. This package provides advanced features tailored for TypeORM, making it suitable for applications that leverage TypeORM's capabilities.

  • nestjs-paginate:

    Choose 'nestjs-paginate' if you need a lightweight and flexible pagination solution that can be easily integrated with various data sources and does not rely on a specific ORM. It is ideal for projects that require a simple pagination mechanism without the overhead of ORM-specific features.

README for nestjs-typeorm-paginate

Coverage Status Awesome Nest Nest Powered npm downloads

Nestjs Typeorm paginate

Pagination helper method for TypeORM repositories or queryBuilders with strict typings

Install

$ yarn add nestjs-typeorm-paginate

or

$ npm i nestjs-typeorm-paginate

If you're using typeorm^0.2.6 please use nestjs-typeorm-paginate^3.2.0 For typeorm^0.3.0 please use nestjs-typeorm-paginate^4.0.0

Usage

Service
Repository
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { CatEntity } from './entities';
import {
  paginate,
  Pagination,
  IPaginationOptions,
} from 'nestjs-typeorm-paginate';

@Injectable()
export class CatService {
  constructor(
    @InjectRepository(CatEntity)
    private readonly repository: Repository<CatEntity>,
  ) {}

  async paginate(options: IPaginationOptions): Promise<Pagination<CatEntity>> {
    return paginate<CatEntity>(this.repository, options);
  }
}
QueryBuilder
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { CatEntity } from './entities';
import {
  paginate,
  Pagination,
  IPaginationOptions,
} from 'nestjs-typeorm-paginate';

@Injectable()
export class CatService {
  constructor(
    @InjectRepository(CatEntity)
    private readonly repository: Repository<CatEntity>,
  ) {}

  async paginate(options: IPaginationOptions): Promise<Pagination<CatEntity>> {
    const queryBuilder = this.repository.createQueryBuilder('c');
    queryBuilder.orderBy('c.name', 'DESC'); // Or whatever you need to do

    return paginate<CatEntity>(queryBuilder, options);
  }
}
Controller
import { Controller, DefaultValuePipe, Get, ParseIntPipe, Query } from '@nestjs/common';
import { CatService } from './cat.service';
import { CatEntity } from './cat.entity';
import { Pagination } from 'nestjs-typeorm-paginate';

@Controller('cats')
export class CatsController {
  constructor(private readonly catService: CatService) {}
  @Get('')
  async index(
    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number = 1,
    @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number = 10,
  ): Promise<Pagination<CatEntity>> {
    limit = limit > 100 ? 100 : limit;
    return this.catService.paginate({
      page,
      limit,
      route: 'http://cats.com/cats',
    });
  }
}

If you use ParseIntPipe on the query params (as in the example), don't forget to also add DefaultValuePipe. See issue 517 for more info.

the route property of the paginate options can also be the short version of an absolute path , In this case, it would be /cats instead of http://cats.com/cats

Example Response

{
  "items": [
    {
      "lives": 9,
      "type": "tabby",
      "name": "Bobby"
    },
    {
      "lives": 2,
      "type": "Ginger",
      "name": "Garfield"
    },
    {
      "lives": 6,
      "type": "Black",
      "name": "Witch's mate"
    },
    {
      "lives": 7,
      "type": "Purssian Grey",
      "name": "Alisdaya"
    },
    {
      "lives": 1,
      "type": "Alistair",
      "name": "ali"
    },
    ...
  ],
  "meta": {
    "itemCount": 10,
    "totalItems": 20,
    "itemsPerPage": 10,
    "totalPages": 5,
    "currentPage": 2
  },
  "links" : {
    "first": "http://cats.com/cats?limit=10",
    "previous": "http://cats.com/cats?page=1&limit=10",
    "next": "http://cats.com/cats?page=3&limit=10",
    "last": "http://cats.com/cats?page=5&limit=10"
  }
}

items: An array of SomeEntity

meta.itemCount: The length of items array (i.e., the amount of items on this page) meta.totalItems: The total amount of SomeEntity matching the filter conditions meta.itemsPerPage: The requested items per page (i.e., the limit parameter)

meta.totalPages: The total amount of pages (based on the limit) meta.currentPage: The current page this paginator "points" to

links.first: A URL for the first page to call | "" (blank) if no route is defined links.previous: A URL for the previous page to call | "" (blank) if no previous to call links.next: A URL for the next page to call | "" (blank) if no page to call links.last: A URL for the last page to call | "" (blank) if no route is defined

Do note that links.first may not have the 'page' query param defined

Find Parameters

@Injectable()
export class CatService {
  constructor(
    @InjectRepository(CatEntity)
    private readonly repository: Repository<CatEntity>,
  ) {}

  async paginate(options: IPaginationOptions): Promise<Pagination<CatEntity>> {
    return paginate<CatEntity>(this.repository, options, {
      lives: 9,
    });
  }
}

Eager loading

Eager loading should work with typeorm's eager property out the box. Like so

import { Entity, OneToMany } from 'typeorm';

@Entity()
export class CatEntity {
  @OneToMany(t => TigerKingEntity, tigerKing.cats, {
    eager: true,
  })
  tigerKings: TigerKingEntity[];
}

// service
class CatService {
  constructor(private readonly repository: Repository<CatEntity>) {}

  async paginate(page: number, limit: number): Promise<Pagination<CatEntity>> {
    return paginate(this.repository, { page, limit });
  }
}

QueryBuilder

However, when using the query builder you'll have to hydrate the entities yourself. Here is a crude example that I've used in the past. It's not great but this is partially what typeORM will do.

const results = paginate(queryBuilder, { page, limit });

return new Pagination(
  await Promise.all(
    results.items.map(async (item: SomeEntity) => {
      const hydrate = await this.someRepository.findByEntity(item);
      item.hydrated = hydrate;

      return item;
    }),
  ),
  results.meta,
  results.links,
);

Raw queries

const queryBuilder = this.repository
  .createQueryBuilder<{ type: string; totalLives: string }>('c')
  .select('c.type', 'type')
  .addSelect('SUM(c.lives)', 'totalLives')
  .groupBy('c.type')
  .orderBy('c.type', 'DESC'); // Or whatever you need to do

return paginateRaw(queryBuilder, options);

Raw and Entities

A similar approach is used for TypeORM's getRawAndEntities

Let's assume there's a joined table that matches each cat with its cat toys. And we want to bring how many toys each cat has.


const queryBuilder = this.repository
  .createQueryBuilder<{ type: string; totalLives: string }>('cat')
    .leftJoinAndSelect('cat.toys', 'toys')
    .addSelect('COUNT(toys)::INTEGER', 'toyCount')
    .groupBy('cat.name');

This will allow us to get the paginated cats information with the additional raw query to build our actual response value. The return pagination object will be the same, but you're now able to handle or map the results and the raw objects as needed.

const [pagination, rawResults] = await paginateRawAndEntities(query, options);
pagination.items.map((item, index) => {
  // we can do what we need with the items and raw results here
  // change your items using rawResults.find(raw => raw.id === item.id)
});
return pagination;

Note about joined tables and raw values

Since the values of the raw results will include all the joined table items as queried, you must make sure to handle the items as needed for your use case. Refer to TypeORM's getRawAndEntities implementation as needed.

The rawResults array will look something like this:

[
    { // Bobby appears 3 times due to the joined query
      "cat_lives": 9,
      "cat_type": "tabby",
      "cat_name": "Bobby",
      "toyCount": 3
    },
    {
      "cat_lives": 9,
      "cat_type": "tabby",
      "cat_name": "Bobby",
      "toyCount": 3
    },
    {
      "cat_lives": 9,
      "cat_type": "tabby",
      "cat_name": "Bobby",
      "toyCount": 3
    },
    {
      "cat_lives": 2,
      "cat_type": "Ginger",
      "cat_name": "Garfield",
      "toyCount": 1
    },
    ...
]

Custom meta data transformer

If you wanted to alter the meta data that is returned from the pagination object. Then use the metaTransformer in the options like so


class CustomPaginationMeta {
  constructor(
    public readonly count: number,
    public readonly total: number,
  ) {}
}

return paginate<MyEntity, CustomPaginationMeta>(this.repository, { 
  page,
  limit,
  metaTransformer: (meta: IPaginationMeta): CustomPaginationMeta => new CustomPaginationMeta(
    meta.itemCount,
    meta.totalItems,
  ),
 });

This will result in the above returning CustomPaginationMeta in the meta property instead of the default IPaginationMeta.

Custom links query params labels

If you want to alter the limit and/or page labels in meta links, then use routingLabels in the options like so


return paginate<MyEntity>(this.repository, { 
  page,
  limit,
  routingLabels: {
    limitLabel: 'page-size', // default: limit
    pageLabel: 'current-page', //default: page
  }
 });

This will result links like http://example.com/something?current-page=1&page-size=3.