首页 / Prisma ORM 入门教程 / 聚合、分组与全文搜索

Prisma ORM 入门教程

聚合、分组与全文搜索

本教程共 54 篇 · 第 25 篇 · 更新于 2026-08-11 · 约 4 分钟阅读

aggregategroupBycountdistinct全文搜索预览功能

本节目标:学会 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 里的字段。

Note

groupBy 不能用 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" }]
Note

distinct 用于去重,可配合 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)