如何使用Typeorm在NestJS中实现分页

Han*_*Han 6 typescript typeorm nestjs

无论如何,通过一次查询即可获取总数并进行记录,而不必执行两次查询。或者如何在两个查询中重用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
    }
}
Run Code Online (Sandbox Code Playgroud)

{计数:10,数据:[{id:1,名称:'David'},{id:2,名称:'Alex'}]}

kad*_*iro 17

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

  • 端点示例:/users?page=4&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
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    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,take)
    
     }
    
    Run Code Online (Sandbox Code Playgroud)
    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,
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)


Iva*_*vic 15

您可以在该项目中找到一些不错的示例。简而言之,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
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到存储库API 。有关Repository类的更多文档可以在这里找到。


Gui*_*eek 7

加起来...

这个中间件检查 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

并在模块中应用。

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

控制器

@Controller('product')
export class TrainingDomainController {
  constructor(private service: YourService) {}

  @Get('paged')
  get(@Query() { take, skip }) {
    return this.service.findAll(take, skip);
  }
}
Run Code Online (Sandbox Code Playgroud)

和服务

@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 };
  }
}
Run Code Online (Sandbox Code Playgroud)

好?

  • 您可能不需要中间件,只需执行标准 DTO,这样就干净多了。 (4认同)
  • 请描述你的答案 (3认同)