
在许多业务场景中,我们需要对关联数据进行统计分析。例如,在一个管理系统里,我们可能需要统计每个管理员(admins)的总支付金额。假设我们有以下 prisma 模型定义:
model admins {
id Int @id @default(autoincrement())
name String
last_name String
phone String @unique
email String? @unique
nic String? @unique
image String?
payments payment[] // 与 payment 模型一对多关系
}
model payment {
id Int @id @default(autoincrement())
amount Int
description String?
date DateTime? @db.Date
admin_id Int
admins admins @relation(fields: [admin_id], references: [id]) // 与 admins 模型多对一关系
}我们的目标是查询每个管理员的总支付金额,并且在结果中包含管理员的姓名(name)和姓氏(last_name),期望的输出格式类似:
{
"admin_id": 1,
"_sum": { "amount": 1650 },
"name": "admin-name",
"last_name": "admin-last-name"
}直接使用 Prisma 的 groupBy 方法进行聚合求和可以轻松实现:
const data = await prisma.payment.groupBy({
by: ["admin_id"],
_sum: {
amount: true,
},
});
console.log(data);
// 结果示例: [{ _sum: { amount: 1650 }, admin_id: 1 }]然而,当前 Prisma 的 groupBy 查询并不支持直接使用 include 或 select 语句来引入关联模型的字段。这意味着我们无法在一次查询中同时完成聚合和关联字段的获取。
为了克服 groupBy 的这一限制,我们可以采用一种分步查询的策略。这种方法的核心思想是:首先执行聚合查询获取分组统计数据,然后利用聚合结果中的关联ID,进行第二次查询以获取所需的关联信息,最后将两次查询的结果进行整合。
首先,我们执行 payment 模型的 groupBy 查询,按 admin_id 分组并计算每个管理员的总支付金额。
const paymentData = await prisma.payment.groupBy({
by: ["admin_id"],
_sum: {
amount: true,
},
});
console.log('聚合结果:', paymentData);
// 示例输出:
// [
// { _sum: { amount: 1650 }, admin_id: 1 },
// { _sum: { amount: 2000 }, admin_id: 2 }
// ]paymentData 将包含每个 admin_id 对应的总金额。
接下来,我们需要遍历 paymentData 中的每一个聚合结果项。对于每个项,我们提取其 admin_id,然后使用 prisma.admins.findUnique 查询来获取对应管理员的 name 和 last_name。由于这是一个异步操作,并且我们需要对所有聚合结果进行处理,因此可以使用 Promise.all 结合 map 方法来并行处理这些查询,提高效率。
const dataWithAdminInfo = await Promise.all(paymentData.map(async (item) => {
// 根据聚合结果中的 admin_id 查询对应的管理员信息
const admin = await prisma.admins.findUnique({
where: { id: item.admin_id },
select: { // 只选择需要的字段,减少数据传输
name: true,
last_name: true
}
});
// 将管理员信息整合到聚合结果中
return {
...item, // 包含 _sum 和 admin_id
name: admin?.name, // 使用可选链操作符处理 admin 可能为 null 的情况
last_name: admin?.last_name
};
}));
console.log('最终整合结果:', dataWithAdminInfo);
// 示例输出:
// [
// { _sum: { amount: 1650 }, admin_id: 1, name: "Admin One", last_name: "Lastname A" },
// { _sum: { amount: 2000 }, admin_id: 2, name: "Admin Two", last_name: "Lastname B" }
// ]通过这种两步走的策略,我们成功地将聚合数据与关联数据结合起来,得到了满足需求的结果。
尽管 Prisma 的 groupBy 功能在直接关联查询方面存在局限,但通过灵活地结合多次查询和数据处理,我们依然能够实现复杂的数据聚合与整合需求。本文介绍的分步查询方案是解决此类问题的有效且常见的模式,适用于大多数情况。在面临大规模数据或严格性能要求时,应进一步评估并考虑更高级的数据库优化策略或直接使用原生 SQL。理解 Prisma 的能力与局限性,并根据实际场景选择最合适的查询策略,是高效开发的关键。
以上就是Prisma 中关联字段聚合求和与数据整合的实践指南的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号