聚合操作 #

一、Count计数 #

1.1 基本计数 #

javascript
// 计数文档总数
Count(Documents(Collection("users")))

// 条件计数
Count(Match(Index("users_by_status"), "active"))

// 索引结果计数
Count(Match(Index("all_products")))

1.2 分组计数 #

javascript
// 按状态分组计数
Map(
  ["active", "inactive", "pending"],
  Lambda("status",
    {
      status: Var("status"),
      count: Count(Match(Index("users_by_status"), Var("status")))
    }
  )
)

1.3 复杂计数 #

javascript
// 多条件计数
Let(
  {
    total: Count(Documents(Collection("orders"))),
    pending: Count(Match(Index("orders_by_status"), "pending")),
    completed: Count(Match(Index("orders_by_status"), "completed")),
    cancelled: Count(Match(Index("orders_by_status"), "cancelled"))
  },
  {
    total: Var("total"),
    pending: Var("pending"),
    completed: Var("completed"),
    cancelled: Var("cancelled"),
    completionRate: Divide(Var("completed"), Var("total"))
  }
)

二、Reduce归约 #

2.1 基本Reduce #

javascript
// 数组求和
Reduce(
  [1, 2, 3, 4, 5],
  Lambda(
    ["acc", "val"],
    Add(Var("acc"), Var("val"))
  ),
  0
)
// 结果: 15

2.2 文档字段求和 #

javascript
// 订单总额
Reduce(
  Map(
    Paginate(Match(Index("all_orders"))),
    Lambda("ref",
      Select(["data", "total"], Get(Var("ref")))
    )
  ),
  Lambda(
    ["acc", "val"],
    Add(Var("acc"), Var("val"))
  ),
  0
)

2.3 复杂Reduce #

javascript
// 计算平均值
Let(
  {
    values: Map(
      Paginate(Match(Index("all_products"))),
      Lambda("ref",
        Select(["data", "price"], Get(Var("ref")))
      )
    ),
    sum: Reduce(
      Var("values"),
      Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
      0
    ),
    count: Count(Var("values"))
  },
  Divide(Var("sum"), Var("count"))
)

2.4 对象Reduce #

javascript
// 构建统计对象
Reduce(
  Map(
    Paginate(Match(Index("all_orders"))),
    Lambda("ref",
      Let(
        { order: Get(Var("ref")) },
        {
          total: Select(["data", "total"], Var("order")),
          count: 1
        }
      )
    )
  ),
  Lambda(
    ["acc", "val"],
    {
      total: Add(Select("total", Var("acc")), Select("total", Var("val"))),
      count: Add(Select("count", Var("acc")), Select("count", Var("val")))
    }
  ),
  { total: 0, count: 0 }
)

三、Group分组 #

3.1 手动分组 #

javascript
// 按状态分组
Map(
  ["active", "inactive", "pending"],
  Lambda("status",
    {
      status: Var("status"),
      users: Map(
        Paginate(Match(Index("users_by_status"), Var("status"))),
        Lambda("ref", Get(Var("ref")))
      )
    }
  )
)

3.2 分组统计 #

javascript
// 分组统计
Map(
  Distinct(
    Map(
      Paginate(Documents(Collection("orders"))),
      Lambda("ref",
        Select(["data", "status"], Get(Var("ref")))
      )
    )
  ),
  Lambda("status",
    {
      status: Var("status"),
      count: Count(Match(Index("orders_by_status"), Var("status"))),
      total: Reduce(
        Map(
          Paginate(Match(Index("orders_by_status"), Var("status"))),
          Lambda("ref",
            Select(["data", "total"], Get(Var("ref")))
          )
        ),
        Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
        0
      )
    }
  )
)

3.3 多字段分组 #

javascript
// 按多个字段分组
Map(
  // 获取所有唯一的(状态, 类型)组合
  Distinct(
    Map(
      Paginate(Documents(Collection("orders"))),
      Lambda("ref",
        Let(
          { doc: Get(Var("ref")) },
          {
            status: Select(["data", "status"], Var("doc")),
            type: Select(["data", "type"], Var("doc"))
          }
        )
      )
    )
  ),
  Lambda("group",
    Let(
      {
        status: Select("status", Var("group")),
        type: Select("type", Var("group"))
      },
      {
        status: Var("status"),
        type: Var("type"),
        count: Count(
          Filter(
            Paginate(Documents(Collection("orders"))),
            Lambda("ref",
              Let(
                { doc: Get(Var("ref")) },
                And(
                  Equals(Select(["data", "status"], Var("doc")), Var("status")),
                  Equals(Select(["data", "type"], Var("doc")), Var("type"))
                )
              )
            )
          )
        )
      }
    )
  )
)

四、统计函数 #

4.1 最大最小值 #

javascript
// 最大值
Reduce(
  Map(
    Paginate(Match(Index("all_products"))),
    Lambda("ref",
      Select(["data", "price"], Get(Var("ref")))
    )
  ),
  Lambda(
    ["acc", "val"],
    If(GT(Var("val"), Var("acc")), Var("val"), Var("acc"))
  ),
  0
)

// 最小值
Reduce(
  Map(
    Paginate(Match(Index("all_products"))),
    Lambda("ref",
      Select(["data", "price"], Get(Var("ref")))
    )
  ),
  Lambda(
    ["acc", "val"],
    If(LT(Var("val"), Var("acc")), Var("val"), Var("acc"))
  ),
  999999999
)

4.2 平均值 #

javascript
// 计算平均值
Let(
  {
    prices: Map(
      Paginate(Match(Index("all_products"))),
      Lambda("ref",
        Select(["data", "price"], Get(Var("ref")))
      )
    ),
    sum: Reduce(
      Var("prices"),
      Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
      0
    ),
    count: Count(Var("prices"))
  },
  If(
    GT(Var("count"), 0),
    Divide(Var("sum"), Var("count")),
    0
  )
)

4.3 中位数 #

javascript
// 计算中位数
Let(
  {
    values: Sort(
      Map(
        Paginate(Match(Index("all_products"))),
        Lambda("ref",
          Select(["data", "price"], Get(Var("ref")))
        )
      ),
      Lambda(["a", "b"], LT(Var("a"), Var("b")))
    ),
    count: Count(Var("values")),
    midIndex: Divide(Var("count"), 2)
  },
  If(
    Equals(Modulo(Var("count"), 2), 0),
    // 偶数个:取中间两个的平均
    Divide(
      Add(
        Select(Var("midIndex"), Var("values")),
        Select(Subtract(Var("midIndex"), 1), Var("values"))
      ),
      2
    ),
    // 奇数个:取中间值
    Select(Var("midIndex"), Var("values"))
  )
)

五、时间聚合 #

5.1 按日期分组 #

javascript
// 按日期分组统计
Map(
  // 获取所有日期
  Distinct(
    Map(
      Paginate(Match(Index("all_orders"))),
      Lambda("ref",
        ToString(Select(["data", "createdAt"], Get(Var("ref"))))
      )
    )
  ),
  Lambda("date",
    {
      date: Var("date"),
      count: Count(
        Filter(
          Paginate(Match(Index("all_orders"))),
          Lambda("ref",
            Equals(
              ToString(Select(["data", "createdAt"], Get(Var("ref")))),
              Var("date")
            )
          )
        )
      )
    }
  )
)

5.2 按月份统计 #

javascript
// 按月份统计
Map(
  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
  Lambda("month",
    Let(
      {
        start: Time(Concat(["2024-", ToString(Var("month")), "-01T00:00:00Z"])),
        end: TimeAdd(Var("start"), 1, "month")
      },
      {
        month: Var("month"),
        count: Count(
          Filter(
            Paginate(Match(Index("all_orders"))),
            Lambda("ref",
              Let(
                { createdAt: Select(["data", "createdAt"], Get(Var("ref"))) },
                And(
                  GTE(Var("createdAt"), Var("start")),
                  LT(Var("createdAt"), Var("end"))
                )
              )
            )
          )
        )
      }
    )
  )
)

5.3 时间范围统计 #

javascript
// 最近7天统计
Let(
  {
    now: Now(),
    days: Map(
      [0, 1, 2, 3, 4, 5, 6],
      Lambda("i",
        TimeSubtract(Var("now"), Var("i"), "day")
      )
    )
  },
  Map(
    Var("days"),
    Lambda("day",
      Let(
        {
          start: Var("day"),
          end: TimeAdd(Var("day"), 1, "day")
        },
        {
          date: Var("day"),
          count: Count(
            Filter(
              Paginate(Match(Index("all_orders"))),
              Lambda("ref",
                Let(
                  { createdAt: Select(["data", "createdAt"], Get(Var("ref"))) },
                  And(
                    GTE(Var("createdAt"), Var("start")),
                    LT(Var("createdAt"), Var("end"))
                  )
                )
              )
            )
          )
        }
      )
    )
  )
)

六、实际应用示例 #

6.1 销售报表 #

javascript
// 销售统计报表
Let(
  {
    orders: Paginate(Match(Index("all_orders"))),
    totalOrders: Count(Var("orders")),
    totalRevenue: Reduce(
      Map(
        Var("orders"),
        Lambda("ref",
          Select(["data", "total"], Get(Var("ref")))
        )
      ),
      Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
      0
    ),
    avgOrderValue: Divide(Var("totalRevenue"), Var("totalOrders")),
    byStatus: Map(
      ["pending", "processing", "shipped", "completed", "cancelled"],
      Lambda("status",
        {
          status: Var("status"),
          count: Count(Match(Index("orders_by_status"), Var("status")))
        }
      )
    )
  },
  {
    summary: {
      totalOrders: Var("totalOrders"),
      totalRevenue: Var("totalRevenue"),
      avgOrderValue: Var("avgOrderValue")
    },
    byStatus: Var("byStatus")
  }
)

6.2 用户分析 #

javascript
// 用户活跃度分析
Let(
  {
    totalUsers: Count(Documents(Collection("users"))),
    activeUsers: Count(Match(Index("users_by_status"), "active")),
    inactiveUsers: Count(Match(Index("users_by_status"), "inactive")),
    byRole: Map(
      ["admin", "user", "moderator"],
      Lambda("role",
        {
          role: Var("role"),
          count: Count(Match(Index("users_by_role"), Var("role")))
        }
      )
    ),
    recentLogins: Count(
      Filter(
        Paginate(Documents(Collection("users"))),
        Lambda("ref",
          GTE(
            Select(["data", "lastLoginAt"], Get(Var("ref")), Time("1970-01-01T00:00:00Z")),
            TimeSubtract(Now(), 7, "day")
          )
        )
      )
    )
  },
  {
    total: Var("totalUsers"),
    active: Var("activeUsers"),
    inactive: Var("inactiveUsers"),
    activeRate: Divide(Var("activeUsers"), Var("totalUsers")),
    byRole: Var("byRole"),
    recentLogins: Var("recentLogins")
  }
)

6.3 产品分析 #

javascript
// 产品销售分析
Let(
  {
    products: Paginate(Match(Index("all_products"))),
    totalProducts: Count(Var("products")),
    inStock: Count(
      Filter(
        Var("products"),
        Lambda("ref",
          GT(Select(["data", "stock"], Get(Var("ref"))), 0)
        )
      )
    ),
    byCategory: Map(
      Distinct(
        Map(
          Var("products"),
          Lambda("ref",
            Select(["data", "categoryId"], Get(Var("ref")))
          )
        )
      ),
      Lambda("category",
        {
          category: Var("category"),
          count: Count(Match(Index("products_by_category"), Var("category")))
        }
      )
    ),
    avgPrice: Let(
      {
        prices: Map(
          Var("products"),
          Lambda("ref",
            Select(["data", "price"], Get(Var("ref")))
          )
        ),
        sum: Reduce(
          Var("prices"),
          Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
          0
        )
      },
      Divide(Var("sum"), Var("totalProducts"))
    )
  },
  {
    total: Var("totalProducts"),
    inStock: Var("inStock"),
    outOfStock: Subtract(Var("totalProducts"), Var("inStock")),
    avgPrice: Var("avgPrice"),
    byCategory: Var("byCategory")
  }
)

七、性能优化 #

7.1 使用索引 #

javascript
// 好的做法:使用索引计数
Count(Match(Index("users_by_status"), "active"))

// 避免:全表扫描
Count(
  Filter(
    Paginate(Documents(Collection("users"))),
    Lambda("ref",
      Equals(Select(["data", "status"], Get(Var("ref"))), "active")
    )
  )
)

7.2 限制数据量 #

javascript
// 限制分页大小
Reduce(
  Map(
    Paginate(Match(Index("all_orders")), { size: 1000 }),
    Lambda("ref",
      Select(["data", "total"], Get(Var("ref")))
    )
  ),
  Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
  0
)

7.3 缓存结果 #

javascript
// 使用Let缓存中间结果
Let(
  {
    orders: Paginate(Match(Index("all_orders"))),
    orderDocs: Map(Var("orders"), Lambda("ref", Get(Var("ref"))))
  },
  {
    total: Count(Var("orders")),
    sum: Reduce(
      Map(Var("orderDocs"), Lambda("doc", Select(["data", "total"], Var("doc")))),
      Lambda(["acc", "val"], Add(Var("acc"), Var("val"))),
      0
    )
  }
)

八、总结 #

聚合操作要点:

操作 说明
Count 计数
Reduce 归约聚合
Map 映射转换
Filter 过滤筛选
Distinct 去重
Sort 排序

下一步,让我们学习事务处理!

最后更新:2026-03-27