Pothos搭配Prisma是否支持Group By?如何实现分组查询
问题描述
现有代码:
export const StockDelivery = builder.prismaObject("StockDelivery", { fields: (t) => ({ id: t.exposeID("id", { nullable: false }), createdAt: t.expose("createdAt", { type: "DateScalar", nullable: false }), modifiedAt: t.expose("modifiedAt", { type: "DateScalar", nullable: false }), expectedAt: t.expose("expectedAt", { type: "DateScalar", nullable: false }), deliveredAt: t.expose("deliveredAt", { type: "DateScalar", nullable: true }), supplier: t.relation("supplier", { nullable: false }), commodity: t.relation("commodity", { nullable: false }), cost: t.exposeFloat("cost", { nullable: false }), qty: t.exposeInt("qty", { nullable: false }), cancelled: t.exposeBoolean("cancelled", { nullable: false }), }), });
想要创建名为shipments的查询,将StockDelivery按expectedAt日期和供应商(supplier)分组。已知Prisma有prisma.stockDelivery.groupBy({...})方法,但不清楚如何和Pothos结合,猜测需要创建StockDelivery prismaObject的自定义变体,但Pothos文档没提分组相关内容,求可行解决方案。
解决方案
Pothos本身没有直接封装Prisma的groupBy能力,但可以通过自定义对象类型+手动编写Resolver的方式实现,步骤如下:
1. 创建分组结果的自定义对象类型
先定义一个新的对象类型,用来承载分组后的数据结构,包含分组键(日期、供应商)以及你需要的聚合字段:
// 定义分组结果类型 export const StockDeliveryGroup = builder.objectType("StockDeliveryGroup", { fields: (t) => ({ expectedAt: t.field({ type: "DateScalar", nullable: false }), supplier: t.field({ type: Supplier, nullable: false }), // 假设你已定义Supplier类型 totalQty: t.int({ nullable: false }), totalCost: t.float({ nullable: false }), count: t.int({ nullable: false }), // 分组内的记录总数 }), });
2. 添加shipments查询字段
在查询类型中添加shipments字段,返回上面定义的分组结果列表:
builder.queryField("shipments", (t) => t.field({ type: [StockDeliveryGroup], args: { // 按需添加过滤参数,比如日期范围 startDate: t.arg({ type: "DateScalar", nullable: true }), endDate: t.arg({ type: "DateScalar", nullable: true }), }, resolve: async (_, args, { prisma }) => { // 调用Prisma的groupBy方法,注意分组键要用外键ID const groups = await prisma.stockDelivery.groupBy({ by: ["expectedAt", "supplierId"], where: { // 按需添加过滤条件 ...(args.startDate && { expectedAt: { gte: args.startDate } }), ...(args.endDate && { expectedAt: { lte: args.endDate } }), cancelled: false, // 排除已取消的记录 }, _sum: { qty: true, cost: true, }, _count: { id: true, }, orderBy: { expectedAt: "asc", }, }); // 手动查询供应商信息,因为groupBy仅返回supplierId const supplierIds = groups.map((g) => g.supplierId); const suppliers = await prisma.supplier.findMany({ where: { id: { in: supplierIds } }, }); const supplierMap = new Map(suppliers.map((s) => [s.id, s])); // 转换为自定义分组类型的结构 return groups.map((group) => ({ expectedAt: group.expectedAt, supplier: supplierMap.get(group.supplierId)!, totalQty: group._sum.qty!, totalCost: group._sum.cost!, count: group._count.id!, })); }, }) );
关键说明
- Prisma的
groupBy只能直接返回分组键(如supplierId)和聚合结果,无法直接关联返回supplier对象,因此需要手动查询供应商并做映射。 - 自定义对象类型可根据需求调整字段,比如只保留分组键,或者添加
_avg、_max等其他聚合值。 - 如果不需要聚合字段,仅需分组后的基础数据,可在
groupBy后通过分组键批量查询对应记录。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

