【问题标题】:how to loop over fields of a struct for query filtering如何遍历结构的字段以进行查询过滤
【发布时间】:2024-01-23 15:23:01
【问题描述】:

我有一个数据库,其中每一行对应一个具有以下字段的结构

type item struct {
    ItemId *string `json:"item_id"`
    OwnerId *string `json:"owner_id"`
    Status *string `json:"status"`
    ... // many more
}

在数据库内部,所有行的所有字段都被填充。现在我想要一个函数,它接受一个 item 对象,其字段可能不会被填充为输入并返回一个 SQL 查询字符串。例如

func FindItems(filter item) string

输入item 用作过滤器。逻辑如下(类python风格)

query = `select * from item_table`
condition = ""
for field, value in filter:
    if value != nil:
        condition = " and " if condition else " where "
        condition += " field=value"
query += condition

如何在 go 中执行此操作?或者有没有更好的方法在 go 中进行过滤?

【问题讨论】:

标签: sql go filter


【解决方案1】:

您可以使用reflect 包来枚举您的结构字段和值:

package main

import (
    "fmt"
    "reflect"
)

type item struct {
    ItemID  *string `json:"item_id"`
    OwnerID *string `json:"owner_id"`
    Status  *string `json:"status"`
}

func FindItemsQuery(filter item) string {
    query := `select * from item_table`
    condition := ""
    val := reflect.ValueOf(filter)
    for i := 0; i < val.NumField(); i++ {
        valField := val.Field(i)
        if !valField.IsNil() {
            if condition != "" {
                condition += " and "
            } else {
                condition += " where "
            }
            condition += fmt.Sprintf("%s=%v", val.Type().Field(i).Tag.Get("json"), valField.Elem())
        }
    }
    return query + condition
}

func main() {
    itemID := "123"
    item := item{ItemID: &itemID}
    fmt.Println(FindItemsQuery(item)) // select * from item_table where item_id=123
}

请记住,使用额外的 json 标记(如 json:"item_id,omitempty")会破坏您的查询。您应该考虑使用自定义结构标签来定义 SQL 字段的名称。

【讨论】:

  • 为什么需要valField.Elem().Interface() 而不是valField.Elem()
  • @nos 我没有意识到fmt.Sprintf 能够处理reflect.Value 类型,你是对的。
最近更新 更多