Orchid ORM 聚合函数

79 阅读3分钟

聚合函数

Orchid ORM 支持丰富的聚合函数(如 countminmaxstring_agg 等),并允许调用自定义聚合函数。每个聚合函数均支持以下配置选项:

type AggregateOptions = {
  distinct?: boolean; // 添加 DISTINCT 修饰符
  order?: OrderArg | OrderArg[]; // 排序参数(等效于 .order())
  filter?: WhereArg; // 过滤条件(等效于 .where())
  filterOr?: WhereArg[]; // OR 逻辑过滤条件(等效于 .orWhere())
  withinGroup?: boolean; // 添加 WITHIN GROUP 子句
  over?: WindowName | OverOptions; // 定义 OVER 子句(窗口函数)
};

基础用法

  • 直接调用:在表实例上直接调用聚合函数,返回单一统计值:

    const totalRecords: number = await db.table.count(); // 统计总记录数
    
  • 在 select 中使用:在 select 回调中调用聚合函数,返回包含统计值的对象数组:

    const stats = await db.table.select({
      count: (q) => q.count(), // 记录数
      avgPrice: (q) => q.avg('price'), // 价格平均值(可能为 null)
    });
    
  • 在 having 中过滤:结合 having 子句对分组结果进行筛选:

    db.table.group('category').having((q) => q.count().gte(10)); // 筛选记录数 ≥10 的分组
    

类型安全与链式操作

聚合函数支持与列操作符链式调用,严格遵循返回类型约束:

// 数值型聚合函数支持数值比较(如 gt、lt)
const hasHighSum = await db.table.sum('sales').gt(1000); 

// 字符串聚合函数支持文本匹配(如 contains)
const hasKeyword = await db.table.stringAgg('tags').contains('featured');

// 布尔聚合函数支持逻辑操作(如 not)
const allInactive = await db.table.boolAnd('isActive').not(true);

组合多个聚合条件

通过 and/or 操作符组合多个聚合结果:

// 同时满足记录数 >5 且总和 <100
const isValid = await db.table
  .count().gt(5)
  .and(db.table.sum('quantity').lt(100));

// 在 select 中组合条件
const { isValid } = await db.table.select({
  isValid: (q) => q.count().gt(5).and(q.sum('quantity').lt(100)),
});

内置聚合函数详解

count

功能:统计记录数或非空列值数量

const total = await db.table.count(); // 统计所有记录
const nonNullNames = await db.table.count('name'); // 统计 name 非空的记录
const groupedCounts = await db.people
  .select('city', { population: (q) => q.count() })
  .group('city'); // 按城市分组统计人口

min/max

功能:获取数值列的最小值 / 最大值(无记录时返回 null

const lowestPrice = await db.product.min('price'); // 最低价格
const highestScoreByCategory = await db.product
  .select('category', { maxScore: (q) => q.max('score') })
  .group('category'); // 按类别分组的最高分数

sum/avg

功能:计算数值列总和 / 平均值(无记录时返回 null

const totalSales = await db.orders.sum('amount'); // 总销售额
const avgRating = await db.movie.avg('rating'); // 平均评分

bitAnd/bitOr

功能:按位与 / 或聚合(返回数值或 null

const combinedFlags = await db.flags.bitAnd('flag'); // 按位与聚合标志位

boolAnd/boolOr/every

功能:布尔值逻辑与 / 或聚合(every 等同于 boolAnd

const allActive = await db.users.boolAnd('isActive'); // 所有用户是否均激活
const anyPending = await db.tasks.boolOr('isPending'); // 是否存在待处理任务

jsonAgg/jsonbAgg

功能:聚合值为 JSON 数组(jsonbAgg 适用于 JSON 操作场景)

const userIds = await db.users.jsonAgg('id'); // 聚合用户 ID 数组
const groupedTags = await db.posts
  .select('category', { tags: (q) => q.jsonbAgg('tags') })
  .group('category'); // 按类别分组的标签数组

jsonObjectAgg/jsonbObjectAgg

功能:构造 JSON 对象(键为字符串,值为列或 SQL 表达式)

const userProfile = await db.users.jsonObjectAgg({
  username: 'name', // 列名映射
  fullName: sql`CONCAT(first_name, ' ', last_name)`, // 原始 SQL 表达式
}); // 返回 { username: string, fullName: string } | null

stringAgg

功能:连接字符串(支持分隔符参数)

const commaNames = await db.students.stringAgg('name', ', '); // 逗号分隔的姓名列表
const groupedEmails = await db.clients
  .select('department', { emails: (q) => q.stringAgg('email', '; ') })
  .group('department'); // 按部门分组的邮箱列表

xmlAgg

功能:连接 XML 列内容

const combinedXml = await db.records.xmlAgg('content'); // 合并 XML 内容