Vendure电商平台分页列表实现指南
前言
在电商系统开发中,分页查询是最常见的功能需求之一。Vendure电商平台提供了一套标准化的分页查询模式,支持分页、筛选和排序功能。本文将详细介绍如何在Vendure中实现自定义实体的分页列表查询。
基础概念
在Vendure中,分页列表查询遵循以下设计模式:
- 实体必须实现
Node
接口(包含id: ID!
字段) - 列表类型必须命名为
<EntityName>List
并实现PaginatedList
接口 - 列表选项输入类型必须命名为
<EntityName>ListOptions
实现步骤
1. 定义GraphQL Schema
首先需要定义查询的GraphQL schema。假设我们有一个表示产品评价的ProductReview
自定义实体:
type ProductReview implements Node {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
product: Product!
productId: ID!
text: String!
rating: Float!
}
type ProductReviewList implements PaginatedList {
items: [ProductReview!]!
totalItems: Int!
}
input ProductReviewListOptions
extend type Query {
productReviews(options: ProductReviewListOptions): ProductReviewList!
}
注意ProductReviewListOptions
输入类型由Vendure在运行时自动生成,无需手动定义。
2. 实现解析器(Resolver)
接下来需要为查询定义解析器:
@Resolver()
export class ProductReviewAdminResolver {
constructor(private productReviewService: ProductReviewService) {}
@Query()
async productReviews(
@Ctx() ctx: RequestContext,
@Args() args: any,
): Promise<PaginatedList<ProductReview>> {
return this.productReviewService.findAll(ctx, args.options || undefined);
}
}
3. 实现服务层(Service)
服务层使用ListQueryBuilder
构建列表查询:
@Injectable()
export class ProductReviewService {
constructor(
private listQueryBuilder: ListQueryBuilder,
) {}
findAll(ctx: RequestContext, options?: ListQueryOptions<ProductReview>): Promise<PaginatedList<ProductReview>> {
return this.listQueryBuilder
.build(ProductReview, options, { relations: ['product'], ctx })
.getManyAndCount()
.then(([items, totalItems]) => ({ items, totalItems }));
}
}
ListQueryBuilder
会自动处理分页、排序和过滤逻辑。
使用示例
完成上述实现后,可以在Admin API中查询评价列表:
query {
productReviews(
options: {
skip: 0
take: 10
sort: {
createdAt: DESC
}
filter: {
rating: {
between: { start: 3, end: 5 }
}
}
}) {
totalItems
items {
id
createdAt
product {
name
}
text
rating
}
}
}
响应示例:
{
"data": {
"productReviews": {
"totalItems": 3,
"items": [
{
"id": "12",
"createdAt": "2023-08-23T12:00:00Z",
"product": {
"name": "Smartphone X"
},
"text": "The best phone I've ever had!",
"rating": 5
}
]
}
}
}
高级筛选功能
Vendure支持复杂的嵌套筛选条件,例如:
query {
productReviews(
options: {
filter: {
_and: [
{ text: { startsWith: "phone" } },
{
_or: [
{ rating: { gte: 4 } },
{ rating: { eq: 0 } }
]
}
]
}
}) {
totalItems
items {
id
text
rating
}
}
}
_and
和_or
操作符可以任意嵌套,实现复杂的筛选逻辑。
自定义属性筛选
默认情况下,ListQueryBuilder
只允许按实体本身的属性筛选。如果需要按关联实体的属性筛选(如product.name
),需要额外配置:
- 扩展GraphQL类型:
input ProductReviewFilterParameter {
productName: StringOperators
}
- 更新服务层:
findAll(ctx: RequestContext, options?: ListQueryOptions<ProductReview>): Promise<PaginatedList<ProductReview>> {
return this.listQueryBuilder
.build(ProductReview, options, {
relations: ['product'],
ctx,
customPropertyMap: {
productName: 'product.name',
}
})
.getManyAndCount()
.then(([items, totalItems]) => ({ items, totalItems }));
}
配置完成后,即可按产品名称筛选:
query {
productReviews(
options: {
filter: {
productName: {
contains: "phone"
}
}
}) {
totalItems
items {
product {
name
}
}
}
}
最佳实践
- 对于关联实体,始终明确指定
relations
数组 - 复杂查询应考虑添加数据库索引
- 分页大小(take)应设置合理上限
- 频繁查询的字段应考虑添加缓存
通过遵循Vendure的分页查询模式,可以快速实现标准化的列表查询功能,同时保持代码的一致性和可维护性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考