Beego ORM无法查询多对多关联字段 如何按Post的created_at排序去重用户
错误根因
你的报错本质是多数关系型数据库(PostgreSQL、开启ONLY_FULL_GROUP_BY的MySQL等)要求DISTINCT查询的排序字段必须出现在SELECT的字段列表中,而Beego ORM查询User模型时默认只会读取User表的字段,加上市面版本的Beego ORM的RelatedSel仅支持一对一、一对多的正向关联,不会自动将多对多关联的Post表字段加入SELECT列表,因此触发字段不存在的报错。
另外如果直接关联Post表,单个用户会对应多条Post记录,直接加DISTINCT也会因为Post的created_at值不同产生重复用户数据,需要先做聚合取每个用户对应的最新/最早Post时间再排序。
可行解决方案
方案1:基于Beego ORM自带方法构造查询
通过Join显式关联多对多中间表和Post表,再用Extra手动补充排序用的聚合字段到SELECT列表中:
import "github.com/astaxie/beego/orm" db := orm.NewOrm() var users []models.User qs := db.QueryTable(new(models.User)).Distinct() // 显式关联多对多中间表和Post表 qs = qs.Join("m2m:Posts", "T1").Join("T1__Post", "T2") // 手动指定SELECT字段,添加聚合得到的用户最新Post发布时间 qs = qs.Extra(orm.Params{ "select": "T0.id, T0.first_name, T0.last_name, T0.full_name, MAX(T2.created_at) as latest_post_created", }) // 按用户主键分组保证去重 qs = qs.GroupBy("T0.id", "T0.first_name", "T0.last_name", "T0.full_name") // 按Post最新发布时间倒序 qs = qs.OrderBy("-latest_post_created") // 补充你原有过滤条件 qs = qs.Filter("T1__tenants_id__in", 你的租户ID列表).Filter("T1__is_inactive", false).Filter("T2__is_inactive", false) // 执行查询 num, err := qs.All(&users)
方案2:直接使用原生SQL查询(更推荐,逻辑更可控)
复杂多表关联查询下直接写原生SQL不受ORM能力限制,适配你的DISTINCT强制要求:
import "github.com/astaxie/beego/orm" db := orm.NewOrm() var users []models.User sql := ` SELECT DISTINCT T0.id, T0.first_name, T0.last_name, T0.full_name FROM "users" T0 INNER JOIN "user_posts" T1 ON T1."users_id" = T0."id" INNER JOIN "post" T2 ON T2."id" = T1."post_id" WHERE T1."tenants_id" IN ? AND T1."is_inactive" = ? AND T2."is_inactive" = ? GROUP BY T0.id, T0.first_name, T0.last_name, T0.full_name ORDER BY MAX(T2.created_at) DESC ` // 执行SQL,结果自动映射到User结构体 num, err := db.Raw(sql, 你的租户ID列表, false, false).QueryRows(&users)
如果你用的是PostgreSQL,也可以将SQL中的DISTINCT替换为DISTINCT ON (T0.id),分组逻辑可以进一步简化。
内容的提问来源于stack exchange,提问作者Aashish Ailawadi
相关产品推荐
相关产品推荐

