如何使用 TypeORM 在 NestJS 中实现分页
How to implement pagination in NestJS with TypeORM
有什么方法可以通过单个查询获取总计数和记录,而不是 运行 将其作为 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'
}]
}
你可以在这个 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
}
}
存储库 API 您可以找到 here. More documentation about Repository
class can be found here。
如果您需要对许多记录进行分页,即多次迭代,(可能在迁移或批量更新期间)。
async getPaginatedResults(query: any, transactionManager?: EntityManager): Promise<any> {
}
总结...
此中间件会检查您是否在 URL 中有 take 和 skip 参数,如果有,它会从字符串转换为数字,如果您不使用默认值。 10 表示接受,0 表示跳过。
take是每页的结果数,skip,应该从哪里开始读取记录。
有了这个,我设置为 GET 方法拦截 "product / paged" 路由。
有了这个,我可以在控制器中检索这些值并传递给 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 };
}
}
好吗?
你也可以看看这个 NestJS 和 TypeORM 包:
我更喜欢使用页面而不是直接跳过
端点示例:/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
}
}
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)
}
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 个单独的查询?
如果不可能,有没有办法在两个查询中重用 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'
}]
}
你可以在这个 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
}
}
存储库 API 您可以找到 here. More documentation about Repository
class can be found here。
如果您需要对许多记录进行分页,即多次迭代,(可能在迁移或批量更新期间)。
async getPaginatedResults(query: any, transactionManager?: EntityManager): Promise<any> {
}
总结...
此中间件会检查您是否在 URL 中有 take 和 skip 参数,如果有,它会从字符串转换为数字,如果您不使用默认值。 10 表示接受,0 表示跳过。
take是每页的结果数,skip,应该从哪里开始读取记录。
有了这个,我设置为 GET 方法拦截 "product / paged" 路由。
有了这个,我可以在控制器中检索这些值并传递给 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 };
}
}
好吗?
你也可以看看这个 NestJS 和 TypeORM 包:
我更喜欢使用页面而不是直接跳过
端点示例:
/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 } }
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) }
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, } }