drazvzi741287 2019-01-24 15:49
浏览 138

go-pg:将postgresql复合类型行的数组解析为结构的golang切片

I am parsing complex PostgreSQL select result into golang structure. I am able to parse an array of text into one field and row of composite type into another, but I also need to make that second field an array of rows, and I fail to parse this array(row()) structure using go-pg driver.

Here is working SQL returning single row as field variants

select p.*,
     array(select url from image i where p.prod_id = i.prod_id) as images,
     (select v from prod_variation v where v.prod_id = p.prod_id limit 1) as variants
     from product p limit 1;

And this is SQL request need to be parsed

select p.*,
    array(select url from image i where p.prod_id = i.prod_id) as images,
    array(select v from prod_variation v where v.prod_id = p.prod_id) as variants
    from product p limit 1;

Notice field variants have array() constructor added and limit 1 removed from subselect.

In golang code Product structure has this field definition

Images    []string    `sql:",array"`
Variants  ProdVariant `sql:"composite:prod_variation"`

I am looking for ability to rewrite second line to something like

Variants  []ProdVariant `sql:",array,composite:prod_variation"`

but this way (and by changing SQL request) I got go-pg error: panic: got slice, wanted struct

Full code is following.

SQL used to create and populate database

CREATE TABLE product (
    prod_id integer primary key,
    name    text,
    price   real
);

CREATE TABLE prod_variation (
    aid           integer primary key,
    prod_id       integer references product(prod_id),
    stock_count   integer,
    color         text
);

CREATE TABLE image (
    prod_id       integer references product(prod_id),
    url           text,
    primary key (url,prod_id)
);

CREATE INDEX on image (prod_id);
CREATE INDEX on prod_variation (prod_id);

INSERT INTO product(prod_id, name, price) VALUES (1, 'Prod 1', 10.0);
INSERT INTO image(prod_id, url) VALUES (1, 'http://url.com/p1-1.jpg');
INSERT INTO image(prod_id, url) VALUES (1, 'http://url.com/p1-2.jpg');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (11, 1, 5, 'red');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (12, 1, 7, 'blue');

INSERT INTO product(prod_id,name, price) VALUES (2, 'Prod 2', 20.0);
INSERT INTO image(prod_id, url) VALUES (2, 'http://url.com/p2-1.jpg');
INSERT INTO image(prod_id, url) VALUES (2, 'http://url.com/p2-2.jpg');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (21, 2, 10, 'black');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (22, 2, 15, 'white');

And here is golang code to select data from postgresql server

package main                                                                                                                                               

import (                                                  
    "log"             

    "github.com/go-pg/pg"                               
    _ "github.com/go-pg/pg/orm"
    "github.com/kylelemons/godebug/pretty"
)

type Product struct {                                                                                                                                     
    tableName struct{} `pg:",discard_unknown_columns"sql:"product"`
    ProdId    uint64   `sql:",pk"`
    Name      string                                             
    Price     float32     `sql:",notnull"`                 
    Images    []string    `sql:",array"`
    Variants  ProdVariant `sql:"composite:prod_variation"`
}                                           

type ProdVariant struct {
    tableName  struct{} `pg:",discard_unknown_columns"sql:"prod_variation"`
    AID        string   `sql:",pk"`
    ProdId     string   `pg:"fk:prod"`
    StockCount int      `sql:",notnull"`
    Color      string
}

type ProductImage struct {
    tableName struct{} `pg:",discard_unknown_columns"sql:"image"`
    ProdId    uint64   `pg:"fk:prod"`
    URL       string
}

func selectProducts(tx *pg.Tx) error {
    queryFormat := `select p.*,
 array(select url from image i where p.prod_id = i.prod_id) as images,
 (select v from prod_variation v where v.prod_id = p.prod_id limit 1) as variants
 from product p limit 1;`
    Res := []Product{}
    if _, err := tx.Query(&Res, queryFormat); err != nil {
            return err
    }
    log.Printf("Select result: %s", pretty.Sprint(&Res))
    return nil
}

func main() {
    opt := pg.Options{Addr: "127.0.0.1:5432", User: "tester", Password: "test12345", Database: "test"}
    conn := pg.Connect(&opt)

    if err := conn.RunInTransaction(selectProducts); err != nil {
            log.Fatalf("Request failed [product]: %s", err)
    }
}

This go code results into this output

2019/01/25 03:15:13 Select result: [{ProdId:   1,
  Name:     "Prod 1",
  Price:    10,
  Images:   ["http://url.com/p1-1.jpg",
             "http://url.com/p1-2.jpg"],
  Variants: {AID:        "11",
             ProdId:     "1",
             StockCount: 5,
             Color:      "red"}}]
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 我的数据无法存进链表里
    • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大
    • ¥15 Oracle中如何从clob类型截取特定字符串后面的字符
    • ¥15 想通过pywinauto自动电机应用程序按钮,但是找不到应用程序按钮信息
    • ¥15 如何在炒股软件中,爬到我想看的日k线
    • ¥15 seatunnel 怎么配置Elasticsearch
    • ¥15 PSCAD安装问题 ERROR: Visual Studio 2013, 2015, 2017 or 2019 is not found in the system.
    • ¥15 (标签-MATLAB|关键词-多址)
    • ¥15 关于#MATLAB#的问题,如何解决?(相关搜索:信噪比,系统容量)
    • ¥500 52810做蓝牙接受端