ent相同列名排序问题解决

前言

最近在开发的时候,需要进行数据库计算,主要是根据表中的某些字段进行汇总计算,但由于数据库表中已有同名字段名,ent 不会使用计算后的指标,默认使用schema中定义的字段,导致无法返回正确的结果。

针对这种情况,我能想到的方法有2种: 1) 不使用同名的字段名 2) 查找ent是否有相关的解决方案。

这里我采用了第二种方法,查找相关的issues, 通过查找相关issue,找到了相关的解决方案: ent 的 sql/modifier 特性。

场景重现

定义一个新的数据库表结构,结构如下:

go 复制代码
func (Ad) Fields() []ent.Field {
    return []ent.Field{
        field.Float("estimated_earnings"),
        field.Int("page_views"),
        field.Time("date"),
        field.Float("page_views_rpm").Optional(),
    }
}

page_views_rpm 字段是由 estimated_earnings 和 page_views 计算而来。

编写相应的查询代码:

go 复制代码
package main

import (
	"context"
	"entgo.io/ent/dialect/sql"
	"fmt"
	_ "github.com/lib/pq"
	"log"
	"modifier-demo/ent"
	"modifier-demo/ent/ad"
	"time"
)

type Ads struct {
	EstimatedEarnings float64   `json:"estimated_earnings"`
	PageViews         int64     `json:"page_views"`
	Date              time.Time `json:"date"`
	PageViewsRpm      float64   `json:"page_views_rpm"`
}

func main() {
	client, err := ent.Open("postgres", "host=127.0.0.1 port=5432 sslmode=disable user=postgres dbname=data_test password=mysecretpassword")
	if err != nil {
		log.Fatalf("failed opening connection to postgres: %v", err)
	}
	defer client.Close()
	// Run the auto migration tool.
	if err := client.Schema.Create(context.Background()); err != nil {
		log.Fatalf("failed creating schema resources: %v", err)
	}
	var a []Ads
	err = client.Debug().Ad.Query().Order(ent.Desc(ad.FieldPageViewsRpm)).GroupBy(ad.FieldDate).Aggregate(func(selector *sql.Selector) string {
		return sql.As(" CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views)*1.0, 0.0)*1000, 0)AS numeric(10,2))", "page_views_rpm")
	}).Scan(context.TODO(), &a)
	if err != nil {
		return
	}
	fmt.Println(a)
}

主要是根据date来汇总并重新计算 page_views_rpm 字段,运行代码后发现没有成功输出,打印后发现ent使用了旧的PageViewsRpm字段进行排序,导致sql无法顺利运行。

sql 复制代码
SELECT "ads"."date",
       CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views) * 1.0, 0.0) * 1000,
                     0) AS numeric(10,2)) AS "page_views_rpm"
FROM "ads"
GROUP BY "ads"."date"
ORDER BY "ads"."page_views_rpm" 

解决

这里可以使用 ent 的 feature sql/modifier 来解决,我们先在 generate.go 开启特性 --feature sql/modifier,然后重新生成代码,使用Modify方法添加自定义修饰符即可,相应的代码如下:

go 复制代码
	err = client.Debug().Ad.Query().Modify(func(s *sql.Selector) {
		s.Select(sql.As(" CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views)*1.0, 0.0)*1000, 0)AS numeric(10,2))", "page_views_rpm")).
			GroupBy("date").
			OrderBy("page_views_rpm")
	}).Scan(context.TODO(), &a)
	if err != nil {
		return
	}

运行修改后的代码,结果顺利输出,相应的sql如下:

sql 复制代码
SELECT CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views) * 1.0, 0.0) * 1000,
                     0) AS numeric(10, 2)) AS "page_views_rpm"
FROM "ads"
GROUP BY "date"
ORDER BY "page_views_rpm"

参考

相关推荐
Java水解10 分钟前
Spring Boot 配置文件深度解析
spring boot·后端
狗头大军之江苏分军16 分钟前
Node.js 性能优化实践,但老板只关心是否能跑
前端·后端
李拾叁的摸鱼日常25 分钟前
Java泛型基本用法与PECS原则详解
java·后端·面试
狗头大军之江苏分军26 分钟前
Node.js 真香,但每次部署都想砸电脑
前端·javascript·后端
帅那个帅1 小时前
go的雪花算法代码分享
开发语言·后端·golang
酒酿萝卜皮1 小时前
Elastic Search 聚合查询
后端
程序员清风1 小时前
阿里二面:新生代垃圾回收为啥使用标记复制算法?
java·后端·面试
sino爱学习1 小时前
Java 三元表达式(?:)的常见坑总结
java·后端
❀͜͡傀儡师1 小时前
Spring Boot函数式编程:轻量级路由函数替代传统Controller
java·spring boot·后端