Beego ORM 不支持 GroupBy() 方法,必须用 Raw() 执行原生 SQL 实现分组查询;需用 Values() 或 ValuesList() 扫描结果,注意参数占位防注入及聚合字段类型手动转换。

QuerySeter 本身不支持 GROUP BY 语法,beego ORM 没有提供原生的 GroupBy() 方法。想实现分组查询,必须绕过 QuerySeter 的链式条件构造,改用 Raw() 执行原生 SQL。
beego ORM 不支持 GroupBy() 方法
你翻遍文档也找不到 qs.GroupBy("city") 或类似调用 —— 这不是遗漏,而是设计上就没实现。所有基于 QuerySeter 的方法(Filter、Limit、OrderBy 等)最终生成的 SQL 都是 SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT 结构,不含 GROUP BY 或聚合函数。
强行在 Filter 中写 "city__in" 或拼接字段名进 expr,不会触发分组,只会报错或静默忽略。
用 Raw() 执行带 GROUP BY 的原生 SQL
这是目前唯一可靠的方式。注意三点:
-
Raw()返回的是RawSeter,和QuerySeter是不同对象,不能混用Filter或OrderBy - 参数绑定必须用
?占位符,不能拼字符串,否则有 SQL 注入风险 - 结果扫描需用
ValuesList()或Values(),因为结构体映射不适用于聚合结果(比如COUNT(*)、AVG(age))
示例:统计各城市用户数
o := orm.NewOrm()
var result []map[string]interface{}
_, err := o.Raw("SELECT city, COUNT(*) AS cnt FROM users GROUP BY city HAVING cnt > ?", 1).ValuesList(&result)
if err != nil {
// handle error
}
// result 形如 [{"city":"shenzhen","cnt":"12"}, {"city":"beijing","cnt":"8"}]
ValuesList 和 Values 的区别与选型
两者都用于接收 Raw() 查询结果,但行为不同:
-
ValuesList(&result):返回二维切片,每行是[]interface{},顺序严格按 SELECT 字段顺序,适合已知字段位置的场景 -
Values(&result):返回[]map[string]interface{},key 是列名(注意大小写,MySQL 默认小写),更易读,推荐用于分组 + 别名场景 - 如果 SQL 中用了别名(如
COUNT(*) AS total),Values()能直接用row["total"]取值;ValuesList()得靠索引row[1],易出错
聚合字段类型需手动转换
即使数据库里 COUNT(*) 是整数,Values() 返回的 row["cnt"] 类型仍是 interface{},且底层常为 string(尤其 MySQL 驱动默认把数字当字符串返回)。不能直接断言为 int:
cnt := row["cnt"].(string) // 安全做法 n, _ := strconv.Atoi(cnt)
更稳妥的做法是统一用 fmt.Sscanf 或 strconv.ParseInt 转换,避免 panic。
分组查询本质是脱离 ORM 映射层的操作,重点不在“怎么写”,而在“怎么安全取值”和“怎么防注入”。别试图给 QuerySeter 加补丁,接受 Raw() 是合理选择。











