Golang中如何使用Sqlx仅扫描结构体字段

Golang中如何使用Sqlx仅扫描结构体字段 我有一个查询,它包含15个列。这个查询是由DBA团队编写的。

REST API团队只想向前端开发者提供其中的5个列。

但是sqlx的Scan方法要求选择所有列。

如何避免这种情况。

2 回复

可以创建一个仅包含所需列的结构体子集:

type WideStruct struct {
	ColumnIDontCareAbout int
	ColumnIDoCareAbout   int
	//...
}

func (w WideStruct) ToSubStruct() SubStruct {
	return SubStruct{
		ColumnIDoCareAbout: w.ColumnIDoCareAbout,
	}
}

type SubStruct struct {
	ColumnIDoCareAbout int
	//...
}

另一个简单的选择是:直接使用自定义的 MarshalJson:

pkg.go.dev

json package - encoding/json - Go Packages

Package json implements encoding and decoding of JSON as defined in RFC 7159.

你也可以为此查询放弃使用 sqlx,转而扫描到局部变量中,并仅填充某个结构体上你需要的属性。

更多关于Golang中如何使用Sqlx仅扫描结构体字段的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中使用sqlx时,可以通过以下方式仅扫描结构体中的特定字段:

方法1:使用sqlx.Selectsqlx.Get配合结构体标签

package main

import (
    "fmt"
    "github.com/jmoiron/sqlx"
    _ "github.com/lib/pq"
)

// 定义只包含需要字段的结构体
type UserResponse struct {
    ID       int    `db:"id"`
    Username string `db:"username"`
    Email    string `db:"email"`
    // 只包含需要的5个字段,忽略其他10个字段
}

func main() {
    db, err := sqlx.Connect("postgres", "user=postgres dbname=test sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    var users []UserResponse
    
    // 方法1A:使用Select
    err = db.Select(&users, `
        SELECT id, username, email, column4, column5, 
               column6, column7, column8, column9, column10,
               column11, column12, column13, column14, column15
        FROM users
    `)
    if err != nil {
        panic(err)
    }

    // 方法1B:使用Get查询单条记录
    var user UserResponse
    err = db.Get(&user, `
        SELECT id, username, email, column4, column5, 
               column6, column7, column8, column9, column10,
               column11, column12, column13, column14, column15
        FROM users WHERE id = $1
    `, 1)
    if err != nil {
        panic(err)
    }

    fmt.Printf("User: %+v\n", user)
}

方法2:使用sqlx.StructScan手动处理

func queryWithPartialScan(db *sqlx.DB) ([]UserResponse, error) {
    rows, err := db.Queryx(`
        SELECT id, username, email, column4, column5, 
               column6, column7, column8, column9, column10,
               column11, column12, column13, column14, column15
        FROM users
    `)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var results []UserResponse
    for rows.Next() {
        var user UserResponse
        // StructScan只会映射结构体中定义的字段
        if err := rows.StructScan(&user); err != nil {
            return nil, err
        }
        results = append(results, user)
    }

    return results, nil
}

方法3:使用匿名结构体(适用于简单场景)

func queryWithAnonymousStruct(db *sqlx.DB) ([]map[string]interface{}, error) {
    var results []map[string]interface{}
    
    rows, err := db.Queryx(`
        SELECT id, username, email, column4, column5, 
               column6, column7, column8, column9, column10,
               column11, column12, column13, column14, column15
        FROM users
    `)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    for rows.Next() {
        // 只提取需要的字段到map中
        row := make(map[string]interface{})
        if err := rows.MapScan(row); err != nil {
            return nil, err
        }
        
        // 创建只包含需要字段的新map
        filtered := map[string]interface{}{
            "id":       row["id"],
            "username": row["username"],
            "email":    row["email"],
            // 只添加需要的字段
        }
        results = append(results, filtered)
    }

    return results, nil
}

方法4:使用自定义扫描器

type PartialScanner struct {
    db *sqlx.DB
}

func (ps *PartialScanner) ScanUsers() ([]UserResponse, error) {
    query := `
        SELECT id, username, email, column4, column5, 
               column6, column7, column8, column9, column10,
               column11, column12, column13, column14, column15
        FROM users
    `
    
    var users []UserResponse
    err := ps.db.Select(&users, query)
    return users, err
}

// 使用示例
func main() {
    db := sqlx.MustConnect("postgres", "user=postgres dbname=test sslmode=disable")
    scanner := &PartialScanner{db: db}
    
    users, err := scanner.ScanUsers()
    if err != nil {
        panic(err)
    }
    
    for _, user := range users {
        fmt.Printf("ID: %d, Username: %s, Email: %s\n", 
            user.ID, user.Username, user.Email)
    }
}

关键点:

  1. sqlx的StructScanSelectGet方法会自动忽略查询结果中多余(结构体未定义)的列
  2. 只需要在结构体中定义需要的字段,并确保db标签与查询中的列名匹配
  3. 查询可以返回所有15列,但结构体只需要定义需要的5列,sqlx会自动处理映射

推荐使用方法1,这是最简洁且符合sqlx设计模式的方式。

回到顶部