在我的数据库中,每一行对应一个结构
type datum struct{
Id *string `json:"task_id"`
Status *string `json:"status"`
AccountId *string `json:"account_id"`
.... // many more fields, all of pointer types
}
用户可以在网页上查询基准的几个字段(例如
account_id
和status
)。服务器将返回所有满足查询条件的数据,并带有字段的投影(例如Id
,account_id
和status
)。现在,我写了一个HTTP处理程序
从请求中将查询提取为基准对象:
body, err := ioutil.ReadAll(r.Body)
condition := datum{}
err = json.Unmarshal(body, &condition)
使用部分填充的基准对象来查询数据库,只有非nil字段才转换为
SELECT ... WHERE ..=..
。查询结果保存在query_result []datum
中将
query_result
写入json对象以进行回复:reply := map[string]interface{}{
"reply": query_result,
}
data, err := json.Marshal(reply)
问题在于,在答复中,许多字段为零,但是我仍然发送它们,这很浪费。另一方面,我不想更改基准结构以包括
omitempty
标记,因为在数据库中,值条目的所有字段均为非零。datum
结构而不是硬代码来定义此新结构? 最佳答案
您有几种选择,根据您的特定情况选择哪种更为浪费/昂贵:
尽管#1不需要注释,而#2则在上面的Gepser中有一定程度的扩展,但是您可以通过以下方法使用自定义编码器解决此问题(想法是重新组装输出,跳过nil个字段):
package main
import (
"fmt"
"encoding/json"
"reflect"
)
type datum struct {
Id *string `json:"task_id"`
Status *string `json:"status"`
AccountId *string `json:"account_id"`
}
type Response struct {
Reply []datum `json:"reply"`
}
func main() {
var query_result []datum
// mocking a query result with records with nil fields
val_id_a := "id-a"
val_status := "status-b"
d1 := datum{
Id: &val_id_a,
Status: &val_status,
}
query_result = append(query_result, d1)
val_id_b := "id-b"
val_account_id := "account-id-b"
d2 := datum{
Id: &val_id_b,
AccountId: &val_account_id,
}
query_result = append(query_result, d2)
reply := &Response{
Reply: query_result,
}
data, err := json.Marshal(reply)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", string(data))
}
// MarshalJSON is a custom JSON marshaller implementation for Response object.
func (r *Response) MarshalJSON() ([]byte, error) {
a := struct {
Reply []map[string]interface{} `json:"reply"`
}{}
for _, v := range r.Reply {
a.Reply = append(a.Reply, converter(v))
}
return json.Marshal(a)
}
// converter converts a struct into a map, skipping fields with nil values.
func converter(in interface{}) map[string]interface{} {
out := make(map[string]interface{})
v := reflect.ValueOf(in)
for i := 0; i < v.NumField(); i++ {
f := v.Type().Field(i)
tag := f.Tag.Get("json")
if tag != "" && !v.Field(i).IsNil() {
out[tag] = v.Field(i).Interface()
}
}
return out
}
关于database - REST API的策略,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41061042/