乐闻世界logo
搜索文章和话题

Nestjs 如何使用用 typeorm 实现分页查询?

7 个月前提问
3 个月前修改
浏览次数202

6个答案

1
2
3
4
5
6

在NestJS中使用TypeORM实现分页查询通常会涉及以下几个步骤:

  1. 创建数据访问服务:首先,你需要在服务中创建一个方法来处理查询逻辑。

  2. 接收分页参数:你需要从客户端接收分页参数,通常是pagelimit,其中page表示当前页码,limit表示每页显示的条目数。

  3. 计算跳过的条目数量:根据分页参数,计算skip值,即你需要跳过的条目数。这可以通过(page - 1) * limit来计算。

  4. 执行查询并返回结果:使用TypeORM提供的findAndCountcreateQueryBuilder方法来执行分页查询,并计算总条目数。

下面是一个具体的例子:

typescript
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { YourEntity } from './entities/your.entity'; @Injectable() export class YourService { constructor( @InjectRepository(YourEntity) private readonly yourEntityRepository: Repository<YourEntity>, ) {} async paginate(page: number = 1, limit: number = 10) { // 计算需要跳过的条目数量 const skip = (page - 1) * limit; // 执行查询并返回结果和总条目数 const [results, total] = await this.yourEntityRepository.findAndCount({ take: limit, skip: skip, // 可以添加其他的查询条件和排序 // where: { ... }, // order: { ... }, }); // 返回分页结果和其他分页信息 return { data: results, // 当前页的数据 count: total, // 总条目数 currentPage: page, // 当前页码 totalPages: Math.ceil(total / limit), // 总页数 }; } }

在这个例子中,服务YourService中的paginate方法接收两个参数pagelimit,它们分别对应于客户端请求的当前页码和每页的条目数量。方法内部,使用findAndCount来执行查询,同时计算总条目数。最后,返回一个对象,包含当前页的数据、总条目数、当前页码和总页数。

在实际应用中,你可能还需要处理边界情况,比如确保页码和每页条目数是正数,以及页码不超过总页数等。此外,还可以根据需要添加排序和过滤条件,来满足具体的业务需求。

2024年6月29日 12:07 回复

简而言之,typeorm有一个专门针对分页查询的用例的非常好的方法 findAndCount

shell
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 } }
2024年6月29日 12:07 回复

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

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

这样,我就设置了仅针对 GET 方法拦截“产品/分页”路由。

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

文件夹

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

模块中应用

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

控制器

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

服务

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

好的?

2024年6月29日 12:07 回复

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

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

    shell
    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/. 更好的方法(处理响应):

    shell
    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) } 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, } }
2024年6月29日 12:07 回复

有 2 个可以满足条件的方法:

createQueryBuilderfindAndCount

shell
const userRepository = dataSource.getRepository(User); const _take = query.take || 10; const _skip = query.skip || 0;

使用createQueryBuilder

shell
const qb = await dataSource .getRepository(User) .createQueryBuilder("user") .orderBy("user.id", "DESC") .take(_take) .skip(_skip); const users = await qb.getMany(); const total = await qb.getCount();

使用findAndCount。通过这种方法,您只需一次调用即可获得全部结果。

shell
const [users, total] = await userRepository.findAndCount({ order: { id: 'DESC' } skip: _skip, take: _take });
2024年6月29日 12:07 回复

你的答案