Golang如何直接将Postgres JSON数据传递到模板?

Golang如何直接将Postgres JSON数据传递到模板? 我可以直接从PostgreSQL获取JSON数据:

SELECT json_agg(hr)::text FROM hr

结果如下:

[map[json_agg:[ {“hr_id”:34,“hr_sign”:“JD”,“hr_job”:“20-0001”,“hr_code”:“PM”,“hr_subject”:“asdf”,“hr_qty”:0.50,“hr_ppu”:1000.00,“hr_sum”:500.00,“hr_date”:“2020-08-22”},

{“hr_id”:35,“hr_sign”:“JD”,“hr_job”:“20-0001”,“hr_code”:“PM”,“hr_subject”:“456”,“hr_qty”:5.25,“hr_ppu”:1000.00,“hr_sum”:5250.00,“hr_date”:“2020-08-22”}]]]

有没有简单的方法可以将这个数据发送到Go模板中?

在另一个讨论中,@Lutzhorn提供的解决方案可能可以作为解决方案的一部分。

Go Playground

Go Playground - The Go Programming Language

我现在想知道,是否有一种自动化的方法可以去掉开头的:

[map[json_agg:

和结尾的:

]]

或者是否有其他方法可以从PostgreSQL获取JSON数据并注入到Go HTML模板中?


更多关于Golang如何直接将Postgres JSON数据传递到模板?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

hr 是什么 PostgreSQL 类型?

更多关于Golang如何直接将Postgres JSON数据传递到模板?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我仍然不理解表的结构。

这个

SELECT json_agg(hr)::text

表明使用了 hrhr 的 PostgreSQL 类型是什么?

你不知道这张表的列吗?为什么要把它们聚合成JSON,然后不得不在Go中再次解析?为什么不直接将列选择到一个匹配的Go结构体中,省去JSON的来回转换呢?

Sibert:

SELECT json_agg(hr)::text

也许这不是从 PostgreSQL 中选择 JSON 以供 Go 使用的最佳方式。

我还没有尝试过,但这看起来很有希望:

https://www.alexedwards.net/blog/using-postgresql-jsonb

也许这不是从 PostgreSQL 中选择 JSON 供 Go 使用的最佳方式。

你能详细说明一下吗?什么方法会更好?

我将其视为从存储过程创建 JSON 输出。在服务器上更快,并且希望在 Go 中进行更少的迭代。你仍然拥有关系数据库管理系统的功能,因为你没有将值存储在 JSON 列中。

{“hr_id”:34,“hr_sign”:“JD”,“hr_job”:“20-0001”,“hr_code”:“PM”,“hr_subject”:“asdf”,“hr_qty”:0.50,“hr_ppu”:1000.00,“hr_sum”:500.00,“hr_date”:“2020-08-22”}

在这个例子中,涉及 int64、varchar、numeric、date 类型的列。它可以是所有类型的列。 除了 json 列 🙂

lutzhorn:

表示使用了 hrhr 的 PostgreSQL 类型是什么?

我对 PostgreSQL 中的 JSON 还不熟悉,但我认为这和 * 的作用差不多。

就像是“创建表 hr 中所有字段的 JSON 聚合”

你可以通过以下方式选择特定的列:

select json_agg((hr_id,hr_date)) from hr

为什么不直接将列选择到匹配的 Go 结构体中,而无需经过 JSON 的往返转换?

因为这个问题:HTML 表格中数值显示为 [53 48 48 46 48 48]

如果对此有解决方法,我将非常高兴。

以下是从 PostgreSQL 获取数据的方式(数值显示为字节切片):

func get(query string) interface{} {
	if len(query) > 0 {
		var list []map[string]interface{}
		rows, err := db.Queryx(query)

		if err != nil {
			log("get error" + err.Error())
		}

		defer rows.Close()

		for rows.Next() {
			row := make(map[string]interface{})
			err = rows.MapScan(row)
			if err != nil {
				log("next " + err.Error())
			}
			list = append(list, row)
		}

		rows.Close()
		
		return (list)
	}
	return nil
}

可以直接将PostgreSQL的JSON数据传递给Go模板,无需手动处理字符串格式。以下是几种方法:

方法1:使用database/sql的RawBytes或string类型

import (
    "database/sql"
    "encoding/json"
    "html/template"
)

func GetJSONData(w http.ResponseWriter, r *http.Request) {
    var jsonData string
    
    // 直接从数据库获取JSON字符串
    err := db.QueryRow("SELECT json_agg(hr)::text FROM hr").Scan(&jsonData)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    // 解析为interface{}以便模板使用
    var data interface{}
    if err := json.Unmarshal([]byte(jsonData), &data); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    tmpl := template.Must(template.ParseFiles("template.html"))
    tmpl.Execute(w, data)
}

方法2:使用json.RawMessage直接传递

func GetJSONDataRaw(w http.ResponseWriter, r *http.Request) {
    var rawJSON json.RawMessage
    
    // 使用json.RawMessage直接接收
    err := db.QueryRow("SELECT json_agg(hr) FROM hr").Scan(&rawJSON)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    // 在模板中作为template.JS使用
    tmpl := template.Must(template.ParseFiles("template.html"))
    tmpl.Execute(w, map[string]interface{}{
        "jsonData": template.JS(rawJSON),
    })
}

方法3:使用结构体映射(推荐)

type HRRecord struct {
    HRID     int     `json:"hr_id"`
    HRSign   string  `json:"hr_sign"`
    HRJob    string  `json:"hr_job"`
    HRCode   string  `json:"hr_code"`
    HRSubject string `json:"hr_subject"`
    HRQty    float64 `json:"hr_qty"`
    HRPPU    float64 `json:"hr_ppu"`
    HRSum    float64 `json:"hr_sum"`
    HRDate   string  `json:"hr_date"`
}

func GetStructuredData(w http.ResponseWriter, r *http.Request) {
    var jsonData []byte
    err := db.QueryRow("SELECT json_agg(hr) FROM hr").Scan(&jsonData)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    var records []HRRecord
    if err := json.Unmarshal(jsonData, &records); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    tmpl := template.Must(template.ParseFiles("template.html"))
    tmpl.Execute(w, records)
}

模板示例(template.html)

<!DOCTYPE html>
<html>
<body>
    <!-- 方法1/3:直接遍历结构化数据 -->
    {{range .}}
    <div>
        <p>ID: {{.HRID}}</p>
        <p>Job: {{.HRJob}}</p>
        <p>Subject: {{.HRSubject}}</p>
        <p>Amount: {{.HRSum}}</p>
    </div>
    {{end}}
    
    <!-- 方法2:作为JavaScript对象使用 -->
    <script>
        var jsonData = {{.jsonData}};
        console.log(jsonData);
        // 在客户端直接使用JSON数据
    </script>
</body>
</html>

方法4:使用pgx驱动直接获取JSON

import (
    "github.com/jackc/pgx/v4"
    "github.com/jackc/pgtype"
)

func GetWithPgx(w http.ResponseWriter, r *http.Request) {
    conn, _ := pgx.Connect(context.Background(), "postgres://...")
    defer conn.Close(context.Background())
    
    var jsonData pgtype.JSON
    err := conn.QueryRow(context.Background(), 
        "SELECT json_agg(hr) FROM hr").Scan(&jsonData)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    var data interface{}
    jsonData.AssignTo(&data)
    
    tmpl := template.Must(template.ParseFiles("template.html"))
    tmpl.Execute(w, data)
}

最简洁的方法是使用json.RawMessage或直接扫描到string类型,然后通过json.Unmarshal解析。这样可以直接将解析后的Go数据结构传递给模板,无需手动处理字符串格式。

回到顶部