悠悠楠杉
网站页面
正文:
在数据分析和业务统计场景中,按日期分组并计算总和是一项高频需求。例如统计每日销售额、用户活跃数等。Prisma 作为现代 Node.js 的 ORM 工具,虽然官方未直接提供 GROUP BY 语法,但通过灵活组合查询仍能高效实现这一功能。以下是具体实现方法及实战技巧。
当需要复杂分组时,可直接使用 Prisma 的 $queryRaw 执行原生 SQL。例如统计 orders 表每日订单总额:
const result = await prisma.$queryRaw`
SELECT
DATE(createdAt) as date,
SUM(amount) as total
FROM Order
GROUP BY DATE(createdAt)
`;
优点:
- 直接利用数据库的聚合能力,性能最优
- 支持复杂日期格式化(如按年、月分组)
缺点:
- 需手动处理 SQL 注入风险
- 返回结果类型需额外定义
如果希望避免原生 SQL,可通过以下步骤实现:
const orders = await prisma.order.findMany({
select: {
amount: true,
createdAt: true
}
});
import { groupBy, sum } from 'lodash';
const grouped = groupBy(orders, order =>
order.createdAt.toISOString().split('T')[0] // 按YYYY-MM-DD分组
);
const dailyTotals = Object.entries(grouped).map(([date, items]) => ({
date,
total: sum(items.map(i => i.amount))
}));
适用场景:
- 数据量较小(万条以内)
- 需跨多表关联计算时
结合 Prisma 的聚合 API 与内存处理,平衡安全性与灵活性:
const rawData = await prisma.order.groupBy({
by: ['createdAt'],
_sum: { amount: true },
orderBy: { createdAt: 'asc' }
});
// 格式化日期并二次聚合
const result = rawData.reduce((acc, item) => {
const dateKey = item.createdAt.toISOString().split('T')[0];
acc[dateKey] = (acc[dateKey] || 0) + item._sum.amount;
return acc;
}, {});
createdAt 字段添加数据库索引skip/take 分页通过上述方法,开发者可根据实际场景选择最适合的解决方案,高效实现日期分组统计需求。