Hasura如何按列中相同值分组并统计数量?
在Hasura中实现按列值分组统计数量
需求说明
需要对analytics表的visitor_id、type、os等列按值分组并统计数量,最终得到类似如下结构的统计结果:
{ "user_id": "user_2Jy9jmL8OIpyb1DpTGYrrtjS77P", "visitor_id": { "null": 41, "user_2JzAMaOW8j01rpsl98McXwBlCkv": 30 }, "type": { "visit": 71, "shares": 0, "clicks": 0 }, "os": { "Windows 10": 28, "iOS 13.2.3": 36, "null": 7 }, "device": { "Desktop": 60, "Mobile": 10, "null": 7 }, "country": { "Japan": 60, "null": 7 }, "browser": { "Chrome": 28, "Mobile Safari": 36, "null": 7 } }
实现方法
Hasura支持通过group_by和聚合函数实现分组统计,需要针对每个目标列单独编写分组查询,再将结果转换为目标结构。
1. 编写分组统计的GraphQL查询
query getAnalyticsGrouped($from: timestamptz, $to: timestamptz, $user_id: String) { # 获取当前用户ID(也可直接使用传入的$user_id参数) user_info: analytics_aggregate(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}) { nodes { user_id } } # visitor_id 分组统计 visitor_stats: analytics_group_by(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}, group_by: [visitor_id]) { visitor_id aggregate { count } } # type 分组统计 type_stats: analytics_group_by(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}, group_by: [type]) { type aggregate { count } } # os 分组统计 os_stats: analytics_group_by(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}, group_by: [os]) { os aggregate { count } } # device 分组统计 device_stats: analytics_group_by(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}, group_by: [device]) { device aggregate { count } } # country 分组统计 country_stats: analytics_group_by(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}, group_by: [country]) { country aggregate { count } } # browser 分组统计 browser_stats: analytics_group_by(where: { created_at: {_gte: $from, _lte: $to}, user_id: {_eq: $user_id}}, group_by: [browser]) { browser aggregate { count } } }
2. 转换查询结果为目标结构
Hasura返回的是分组列表格式,需要通过前端代码转换为键值对结构。以JavaScript为例:
// 假设queryResult是Hasura返回的查询结果 const formatAnalyticsStats = (queryResult, userId) => { // 通用转换函数:将分组列表转为键值对,处理null值 const convertToKeyValue = (stats) => { return stats.reduce((acc, item) => { const keyField = Object.keys(item).find(k => k !== 'aggregate'); const value = item[keyField] ?? 'null'; acc[value] = item.aggregate.count; return acc; }, {}); }; return { user_id: queryResult.user_info.nodes[0]?.user_id || userId, visitor_id: convertToKeyValue(queryResult.visitor_stats), // type字段需要补全预设的0值项 type: { visit: 0, shares: 0, clicks: 0, ...convertToKeyValue(queryResult.type_stats) }, os: convertToKeyValue(queryResult.os_stats), device: convertToKeyValue(queryResult.device_stats), country: convertToKeyValue(queryResult.country_stats), browser: convertToKeyValue(queryResult.browser_stats) }; };
关键说明
analytics_group_by是Hasura自动生成的分组查询字段,指定group_by参数为要统计的列,通过aggregate.count获取该分组的记录数。- 对于需要展示0值的列(如
type中的shares、clicks),因为Hasura只会返回数据库中存在的分组值,所以需要在转换时手动补全预设项。 - 数据库中的
null值会被Hasura作为独立分组返回,转换时可将其映射为字符串"null"。
内容的提问来源于stack exchange,提问作者user20951184
相关产品推荐
相关产品推荐

