如何对搜索结果进行分页?

How to paginate searched results?

如何使用游标对搜索结果进行分页?

这是我查询数据的功能,有问题,因为当我加载更多数据时,有些项目与搜索查询无关?

    @UseMiddleware(isAuthenticated)
    @Query(() => PaginatedQuizzes)
    async quizzes(
        @Arg('limit', () => Int) limit: number,
        @Arg('cursor', () => String, { nullable: true }) cursor: string | null,
        @Arg('query', () => String, { nullable: true }) query: string | null
    ): Promise<PaginatedQuizzes> {
        const realLimit = Math.min(50, limit);
        const realLimitPlusOne = realLimit + 1;

        const qs = await getConnection()
            .getRepository(Quiz)
            .createQueryBuilder('q')
            .leftJoinAndSelect('q.author', 'author')
            .leftJoinAndSelect('q.questions', 'questions')

        if (query) {
            const formattedQuery = query.trim().replace(/ /g, ' <-> ');

            qs.where(
                `to_tsvector('simple',q.title) @@ to_tsquery('simple', :query)`,
                {
                    query: `${formattedQuery}:*`,
                }
            ).orWhere(
                `to_tsvector('simple',q.description) @@ to_tsquery('simple', :query)`,
                {
                    query: `${formattedQuery}:*`,
                }
            );
        }

        if (cursor) {
            qs.where('q."created_at" < :cursor', {
                cursor: new Date(parseInt(cursor)),
            });
        }

        const quizzes = await qs
            .orderBy('q.created_at', 'DESC')
            .take(realLimitPlusOne)
            .getMany();

        return {
            quizzes: (quizzes as [Quiz]).slice(0, realLimit),
            hasMore: (quizzes as [Quiz]).length === realLimitPlusOne,
        };
    }

嘿,我一直在使用这个很酷的包来分页 table 检查一下 here

import { buildPaginator } from 'typeorm-cursor-pagination';

const paginator = buildPaginator({
  entity: User,
  paginationKeys: ['id'],
  query: {
    limit: 10,
    order: 'ASC',
  },
});
const { data, cursor } = await paginator.paginate(queryBuilder);

您可以使用自定义系统,而不是安装可能存在漏洞的繁重软件包。

这是一个示例 controller,使用 limitpage 参数获取 x 页面

上的 n 元素
@Get('elements/:limit/:page')
  getElementsWithPagination(
    @Param('limit') limit: number,
    @Param('page') page: number,
  ): Promise<ElementsEntity[]> {
    return this.elementsService.getElementsWithPagination(limit, page);
  }

这里是 service 访问您的存储库

async getElementsWithPagination(
    limit: number,
    page: number,
  ): Promise<ElementsEntity[]> {
    return this.elementsRepository.findElementsWithPagination(limit, page);
  }

最后是带有查询参数的 repository,从最新到最旧排序

async findElementsWithPagination(limit, page): Promise<ElementsEntity[]> {
    return this.find({
      take: limit,
      skip: limit * (page - 1),
      order: { createdAt: 'DESC' },
    });
  }

感谢这个系统,您可以逐页查询 n 个元素。

非常感谢您的回复,但我能够使用查找选项自行解决,

    @UseMiddleware(isAuthenticated)
    @Query(() => PaginatedQuizzes)
    async quizzes(
        @Arg('limit', () => Int) limit: number,
        @Arg('cursor', () => String, { nullable: true }) cursor: string | null,
        @Arg('query', () => String, { nullable: true }) query: string | null
    ): Promise<PaginatedQuizzes> {
        const realLimit = Math.min(20, limit);
        const realLimitPlusOne = realLimit + 1;

        let findOptionInitial: FindManyOptions = {
            relations: [
                'author',
                'questions',
            ],
            order: {
                created_at: 'DESC',
            },
            take: realLimitPlusOne,
        };

        let findOption: FindManyOptions;

        if (cursor && query) {
            const formattedQuery = query.trim().replace(/ /g, ' <-> ');

            findOption = {
                ...findOptionInitial,
                where: [
                    {
                        description: Raw(
                            (description) =>
                                `to_tsvector('simple', ${description}) @@ to_tsquery('simple', :query)`,
                            {
                                query: formattedQuery,
                            }
                        ),
                        created_at: LessThan(new Date(parseInt(cursor))),
                    },
                    {
                        title: Raw(
                            (title) =>
                                `to_tsvector('simple', ${title}) @@ to_tsquery('simple', :query)`,
                            {
                                query: formattedQuery,
                            }
                        ),
                        created_at: LessThan(new Date(parseInt(cursor))),
                    },
                ],
            };
        } else if (cursor) {
            findOption = {
                ...findOptionInitial,
                where: {
                    created_at: LessThan(new Date(parseInt(cursor))),
                },
            };
        } else if (query) {
            const formattedQuery = query.trim().replace(/ /g, ' <-> ');

            findOption = {
                ...findOptionInitial,
                where: [
                    {
                        description: Raw(
                            (description) =>
                                `to_tsvector('simple', ${description}) @@ to_tsquery('simple', :query)`,
                            {
                                query: formattedQuery,
                            }
                        ),
                    },
                    {
                        title: Raw(
                            (title) =>
                                `to_tsvector('simple', ${title}) @@ to_tsquery('simple', :query)`,
                            {
                                query: formattedQuery,
                            }
                        ),
                    },
                ],
            };
        } else {
            findOption = findOptionInitial;
        }

        const quizzes = await Quiz.find(findOption as FindManyOptions);

        return {
            quizzes: (quizzes as [Quiz]).slice(0, realLimit),
            hasMore: (quizzes as [Quiz]).length === realLimitPlusOne,
        };
    }