聚合、分组与全文搜索
本教程共 54 篇 · 第 25 篇 · 更新于 2026-08-11 · 约 4 分钟阅读
本节目标:学会 aggregate / groupBy / count 做统计,掌握全文搜索的开启与用法。
统计「总数、平均、最大」和搜索关键词,是查询里最后两块拼图。Prisma 的聚合 API 覆盖常见统计,全文搜索则把关键词匹配交给数据库原生能力。
aggregate:一次算多个统计值
aggregate 在数值字段上算 _count、_avg、_sum、_min、_max:
const result = await prisma.post.aggregate({
_count: { id: true },
_avg: { views: true },
_max: { views: true },
});
// { _count: { id: 42 }, _avg: { views: 1250.5 }, _max: { views: 9999 } }
可以加 where、orderBy、take,统计前先过滤:
await prisma.order.aggregate({
_sum: { total: true },
where: { status: "PAID" },
});
_avg / _sum 只支持数值字段(Int、Float、Decimal、BigInt),_min / _max 还能用于 DateTime 和 String——「最早创建时间」「最长的名字」都行。
Note对可空字段聚合时,结果可能是 null,唯独 _count 没有数据时返回 0。这是刻意设计:null 表示「没有数据」,0 是「真值就是 0」,两者要区分。
groupBy:按字段分组统计
groupBy 把记录按字段值分组,再对每组做聚合:
await prisma.order.groupBy({
by: ["status"],
_sum: { total: true },
_count: { _all: true },
});
// 每个状态一组的销售额与订单数
by 接受数组,多字段分组也行;单个字段时可以写字符串简写。groupBy 有两层过滤:
await prisma.order.groupBy({
by: ["status"],
where: { email: { contains: "prisma.io" } }, // 分组前过滤记录
_sum: { total: true },
having: { total: { _avg: { gt: 100 } } }, // 分组后过滤组
});
where 先缩小数据集(能走索引),having 再筛掉不合格的组。having 只能引用聚合值或 by 里的字段。
NotegroupBy 不能用 select,by 里的字段会自动返回。配合 skip / take 分页时必须同时给出 orderBy,且 orderBy 只能排 by 字段或聚合结果。
count 的三种形态
count 返回数字,能带 where:
const total = await prisma.post.count({
where: { published: true },
});
按字段统计非空值个数:
await prisma.user.count({
select: { _all: true, name: true },
});
// { _all: 30, name: 10 }:30 个用户,10 个填了名字
关系计数用 include / select 里的 _count,第 21、24 章已讲过。
distinct:去重
distinct 按字段组合去重:
await prisma.user.findMany({
distinct: ["role"],
select: { role: true },
});
// [{ role: "USER" }, { role: "ADMIN" }]
Notedistinct 用于去重,可配合 select / include 使用。去重前先 orderBy,才能确定每组保留哪一条;数据量大时优先考虑 groupBy 或原始查询。
全文搜索:开启与语法
先看它和 contains 的区别。contains 是子串匹配(%关键词%),全文搜索则做分词、词干处理,还能算相关度排名。PostgreSQL 上这是预览功能(Preview),要在生成器里开启:
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
previewFeatures = ["fullTextSearchPostgres"]
}
开启后重新 npx prisma generate。查询语法用 search 操作符:
await prisma.post.findMany({
where: {
title: { search: "cat & dog" }, // 同时包含 cat 和 dog
},
});
语法速记:
| 符号 | 含义 | 示例 |
|---|---|---|
| & | 且 | cat & dog |
| | | 或 | cat | dog |
| ! | 非 | !cat |
| word:* | 前缀匹配 | data:* 匹配 database |
Warning& | ! 是保留符号。用户输入直接拼进 search 会破坏语法,先转义或加引号再传。
Note全文搜索是预览功能(Preview),生产使用前需确认。MySQL 的全文搜索是正式功能,PostgreSQL 需要预览开关。MongoDB 在 v7 不支持全文搜索,相关用法留 v6.19。
建立索引与相关度排序
PostgreSQL 的全文搜索依赖 tsvector。索引要手动建,写进迁移文件:
CREATE INDEX post_fts_idx ON "Post"
USING GIN (to_tsvector('english', title || ' ' || content));
按相关度排序用 _relevance:
await prisma.post.findMany({
where: { title: { search: "prisma" } },
orderBy: {
_relevance: { fields: ["title"], search: "prisma", sort: "desc" },
},
});
Tip搜索常和普通过滤组合:先过滤状态、分类等条件缩小范围,再做全文搜索。tsvector 的解析语言(上面是 english)按内容语言配置,中文分词需要额外扩展,简单场景可先用 contains +
mode: "insensitive"。
参考来源
- Prisma 官方文档:Aggregation, grouping, and summarizing
- Prisma 官方文档:Full-text search
- Mapagam:Working with Aggregations / Implementing Full-Text Search
- Tech Insider:Prisma ORM Tutorial(Full-Text Search)