【问题标题】:How to implement pagination in NestJS with TypeORM如何使用 TypeORM 在 NestJS 中实现分页
【发布时间】:2019-05-24 03:39:33
【问题描述】:

有没有办法通过单个查询来获取总计数和记录,而不是将其作为 2 个单独的查询运行?

如果不可能,有没有办法在两个查询中重用 where 条件?

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'
    }]
}

【问题讨论】:

    标签: typescript nestjs typeorm


    【解决方案1】:

    我更喜欢使用页面而不是直接跳过

    • 端点示例:/users?page=4&amp;take=3

      async findAll(query): Promise<Paginate> {
          const take = query.take || 10
          const page=query.page || 1;
          const skip= (page-1) * take ;
          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
          }
      }
      

      2/.更好的方法(处理响应):

       async findAll(query): Promise<Paginate> {
           const take = query.take || 10
           const page=query.page || 1;
           const skip= (page-1) * take ;
           const keyword = query.keyword || ''
      
           const data = await this.userRepository.findAndCount(
               {
                   where: { name: Like('%' + keyword + '%') }, order: { name: "DESC" },
                   take: take,
                   skip: skip
               }
           );
           return paginateResponse(data ,page,limit)
      
       }
      
      export function paginateResponse(data,page,limit) {
        const [result, total]=data;
        const lastPage=Math.ceil(total/limit);
        const nextPage=page+1 >lastPage ? null :page+1;
        const prevPage=page-1 < 1 ? null :page-1;
        return {
          statusCode: 'success',
          data: [...result],
          count: total,
          currentPage: page,
          nextPage: nextPage,
          prevPage: prevPage,
          lastPage: lastPage,
        }
      }
      

    【讨论】:

      【解决方案2】:

      你也可以看看这个用于 NestJS 和 TypeORM 的包:

      https://github.com/nestjsx/nestjs-typeorm-paginate

      【讨论】:

        【解决方案3】:

        总结...

        此中间件检查 URL 中是否有 take 和 skip 参数,如果有,它会从字符串转换为数字,如果你不使用默认值。 10 为拍摄,0 为跳过。

        take 是每页和跳过的结果数,它应该从哪里开始读取记录。

        这样,我设置为 GET 方法拦截“产品/分页”路由。

        这样我可以在控制器中检索这些值并传递给 TypeORM 或 SQL 查询。

        @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();
          }
        }
        

        并在模块中应用。

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

        控制器

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

        和服务

        @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 };
          }
        }
        

        好吗?

        【讨论】:

        • 请描述你的答案
        • 这个中间件检查你是否在 URL 中有 take 和 skip 参数,如果有,它会从字符串转换为数字,如果你不使用默认值。 10 为拍摄,0 为跳过。 take 是每页和 skip 的结果数,它应该从哪里开始读取记录。有了这个,我设置为 GET 方法拦截“产品/分页”路由。有了这个,我可以在控制器中检索这些值并传递给 TypeORM 或 SQL 查询。
        • 您可能不需要中间件,只需执行标准 DTO,它会干净得多。
        【解决方案4】:

        如果您需要对许多记录进行分页,即多次迭代(可能在迁移或大规模更新期间)。

        async getPaginatedResults(query: any, transactionManager?: EntityManager): Promise<any> {
        
        }
        

        【讨论】:

          【解决方案5】:

          您可以在project 中找到一些不错的示例。简而言之,typeorm 有一个非常好的方法,专门针对这个用例 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
              }
          }
          

          您可以找到 here 的存储库 API。更多关于Repository 类的文档可以在here 找到。

          【讨论】:

          • 非常感谢,这两个网址对像我这样刚开始学习打字稿的新手很有用^^
          • 欢迎您!如果您也可以为答案投票,我将不胜感激。
          • 很好的例子,但请注意 Like('%' + keyword + '%') 仅适用于 SQL 数据库,不适用于 mongodb。
          • 我在我的模型上找不到 findAndCount... 只能找到
          • 如果您想使用 ClassSerializerInterceptor,我对其进行了一些更改,使其接受 [Array&lt;PlainLiteralObject&gt;, number] 类型的返回值。在这种情况下很有用。所以你可以简单地返回getManyAndCount(),无论如何数据都会被序列化。看看:gist.github.com/ericjeker/08f719aae3b730c820b62136efec9708
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-28
          • 2022-07-24
          • 2019-06-04
          • 2021-09-08
          • 2021-04-23
          • 1970-01-01
          • 2020-12-22
          相关资源
          最近更新 更多