การลบฟิลด์ออกจาก struct หรือซ่อนไว้ในการตอบกลับ JSON


181

ฉันได้สร้าง API ใน Go แล้วเมื่อถูกเรียกให้ทำการคิวรีสร้างอินสแตนซ์ของ struct จากนั้นเข้ารหัส encode นั้นเป็น JSON ก่อนที่จะส่งกลับไปยังผู้โทร ตอนนี้ฉันต้องการอนุญาตให้ผู้เรียกสามารถเลือกเขตข้อมูลเฉพาะที่พวกเขาต้องการส่งคืนโดยส่งผ่านพารามิเตอร์ "เขตข้อมูล" GET

ซึ่งหมายความว่าขึ้นอยู่กับค่าของฟิลด์ struct ของฉันจะเปลี่ยนไป มีวิธีการลบเขตข้อมูลจาก struct หรือไม่? หรืออย่างน้อยก็ซ่อนไว้ในการตอบสนอง JSON แบบไดนามิก? (หมายเหตุ: บางครั้งฉันมีค่าว่างดังนั้นแท็ก JSON omitEmpty จะไม่ทำงานที่นี่) หากไม่มีสิ่งเหล่านี้เป็นไปได้มีข้อเสนอแนะเกี่ยวกับวิธีที่ดีกว่าในการจัดการกับสิ่งนี้หรือไม่ ขอบคุณล่วงหน้า.

structs รุ่นที่เล็กกว่าที่ฉันใช้อยู่ด้านล่าง:

type SearchResult struct {
    Date        string      `json:"date"`
    IdCompany   int         `json:"idCompany"`
    Company     string      `json:"company"`
    IdIndustry  interface{} `json:"idIndustry"`
    Industry    string      `json:"industry"`
    IdContinent interface{} `json:"idContinent"`
    Continent   string      `json:"continent"`
    IdCountry   interface{} `json:"idCountry"`
    Country     string      `json:"country"`
    IdState     interface{} `json:"idState"`
    State       string      `json:"state"`
    IdCity      interface{} `json:"idCity"`
    City        string      `json:"city"`
} //SearchResult

type SearchResults struct {
    NumberResults int            `json:"numberResults"`
    Results       []SearchResult `json:"results"`
} //type SearchResults

ฉันเข้ารหัสและแสดงผลการตอบสนองเช่นนั้น:

err := json.NewEncoder(c.ResponseWriter).Encode(&msg)

7
@Jacob ตามคำตอบล่าสุดของ PuerkitoBio ฉันคิดว่าคุณอ่านคำถามผิด การยอมรับ (ปัจจุบัน) อาจไม่ใช่ "คำตอบที่ถูกต้อง" สำหรับคำถามของคุณแต่สำหรับคนที่ถามที่นี่! คำตอบที่โหวตสูงสุด (ปัจจุบัน) อาจตอบคำถามของคุณแต่ไม่เหมาะสมสำหรับคำถามนี้!
Dave C

คำตอบ:


277

แก้ไข: ฉันสังเกตเห็น downvotes ไม่กี่และดูคำถามและคำตอบนี้อีกครั้ง คนส่วนใหญ่ดูเหมือนจะพลาดว่า OP ขอให้ฟิลด์เลือกแบบไดนามิกโดยอิงตามรายการของฟิลด์ที่ผู้โทรจัดเตรียมไว้ คุณไม่สามารถทำได้ด้วยแท็ก json struct ที่กำหนดขึ้นแบบสแตติก

หากสิ่งที่คุณต้องการคือการเสมอข้ามสนามไป JSON เข้ารหัสแล้วในการใช้หลักสูตรjson:"-"ที่จะไม่สนใจสนาม (ยังทราบว่านี้ไม่ได้จำเป็นต้องใช้ถ้าข้อมูลของคุณ unexported - เขตข้อมูลเหล่านั้นจะถูกละเลยเสมอโดยการเข้ารหัส JSON) ที่ แต่นั่นไม่ใช่คำถามของ OP

เพื่ออ้างถึงความคิดเห็นในjson:"-"คำตอบ:

[ json:"-"คำตอบ] นี้เป็นคำตอบที่คนส่วนใหญ่ลงมาจากการค้นหาที่นี่ แต่มันไม่ใช่คำตอบของคำถาม


ฉันจะใช้อินเทอร์เฟซของแผนที่ [สตริง] {} แทนที่จะเป็นโครงสร้างในกรณีนี้ คุณสามารถลบเขตข้อมูลได้อย่างง่ายดายโดยการโทรdeleteบิวด์อินบนแผนที่เพื่อลบฟิลด์

นั่นคือถ้าคุณไม่สามารถค้นหาเฉพาะสำหรับเขตข้อมูลที่ร้องขอในสถานที่แรก


5
คุณมักจะไม่ต้องการทิ้งคำจำกัดความประเภทของคุณอย่างสิ้นเชิง นั่นจะน่ารำคาญเมื่อคุณต้องการเขียนวิธีอื่นในประเภทนี้ที่เข้าถึงฟิลด์เหล่านั้น การใช้สื่อกลางmap[string]interface{}นั้นสมเหตุสมผล แต่ก็ไม่ต้องการให้คุณทิ้งนิยามประเภทของคุณไป
jorelli

1
คำตอบอื่น ๆ คือคำตอบที่แท้จริงสำหรับคำถามนี้
Jacob

1
ข้อเสียเปรียบที่เป็นไปได้ของการลบคือบางครั้งคุณอาจต้องการสนับสนุนมุมมอง json หลายมุมของ struct ของคุณ (แผนที่) ตัวอย่างเช่นมุมมอง json สำหรับไคลเอ็นต์ที่ไม่มีฟิลด์ที่ละเอียดอ่อนและมุมมอง json สำหรับฐานข้อมูลที่มีฟิลด์ที่ละเอียดอ่อน โชคดีที่มันยังคงเป็นไปได้ที่จะใช้ struct เพียงแค่ดูคำตอบของฉัน
Adam Kurkiewicz

สิ่งนี้ใช้ได้กับฉันเพราะฉันต้องการเฉพาะเจาะจงIdแต่ไม่ต้องการคืนโครงสร้าง json ทั้งหมด ขอบคุณสำหรับสิ่งนี้!
Louie Miranda

155

ใช้ `json:" - "`

// Field is ignored by this package.
Field int `json:"-"`

// Field appears in JSON as key "myName".
Field int `json:"myName"`

// Field appears in JSON as key "myName" and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `json:"myName,omitempty"`

// Field appears in JSON as key "Field" (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `json:",omitempty"`

doc: http://golang.org/pkg/encoding/json/#Marshal


14
ฉันไม่เห็นด้วย @Jacob เพราะ OP บอกว่าพวกเขาต้องการควบคุมฟิลด์เอาต์พุตแบบไดนามิกโดยยึดตามรายการสตริงข้อความค้นหาไปยัง API ตัวอย่างเช่นหากผู้เรียกใช้ API ขอเฉพาะอุตสาหกรรมและประเทศคุณจะต้องลบที่เหลือ นี่คือเหตุผลที่คำตอบ "ถูก" ถูกทำเครื่องหมายเป็นคำตอบสำหรับคำถามนี้ คำตอบที่ได้รับการโหวตอย่างสูงนี้มีไว้สำหรับการทำเครื่องหมายฟิลด์อย่างชัดเจนไม่เคยมีมาให้ในตัว หากคุณต้องการให้เป็นแบบไดนามิกคำตอบที่ถูกต้องคือคำตอบ
eduncan911

12
นี่คือคำตอบที่คนส่วนใหญ่ลงท้ายด้วยการค้นหาที่ต้องการ แต่ไม่ใช่คำตอบของคำถาม
Filip Haglund

5
ตามที่ระบุไว้แล้ว OP ได้ขอวิธีการในรูปแบบ DTO แบบไดนามิก
codepushr

54

อีกวิธีในการทำเช่นนี้คือการมีโครงสร้างของพอยน์เตอร์ที่มี,omitemptyแท็ก หากพอยน์เตอร์เป็นศูนย์ฟิลด์จะไม่ถูกมาร์แชล

วิธีนี้จะไม่ต้องการการสะท้อนเพิ่มเติมหรือการใช้แผนที่อย่างไม่มีประสิทธิภาพ

ตัวอย่างเช่น jorelli โดยใช้วิธีนี้: http://play.golang.org/p/JJNa0m2_nw


3
+1 เห็นด้วยอย่างสมบูรณ์ ฉันใช้กฎนี้ / หลอกลวงตลอดเวลาด้วย marshalers ในตัว (และยังสร้างตัวอ่าน / นักเขียน CSV ตามกฎนี้ด้วย! - ฉันอาจโอเพนซอร์ซทันทีที่เป็นแพ็คเกจ csv go อีกชุดหนึ่ง) OP ไม่สามารถตั้งค่า * Country value เป็นศูนย์ได้และจะถูกละเว้น และที่ยอดเยี่ยมที่คุณมอบให้เป็นสิ่งที่ดีคุณพิมพ์ play.golang เช่นกัน
eduncan911

2
แน่นอนว่าวิธีการนั้นต้องการการสะท้อนการ marshaling json-to-struct ของ stdlib มักจะใช้การสะท้อน (ที่จริงมันมักจะใช้ระยะเวลาการสะท้อนแผนที่หรือ struct หรืออะไรก็ตาม)
mna

ใช่ แต่ไม่ต้องการการสะท้อนเพิ่มเติมโดยใช้อินเทอร์เฟซซึ่งคำตอบอื่น ๆ แนะนำ
Druska

14

คุณสามารถใช้reflectแพคเกจเพื่อเลือกฟิลด์ที่คุณต้องการโดยสะท้อนให้เห็นถึงแท็กของฟิลด์และเลือกjsonค่าแท็ก กำหนดวิธีการใน searchresults คุณพิมพ์เลือกว่าเขตข้อมูลที่คุณต้องการและผลตอบแทนที่พวกเขาเป็นmap[string]interface{}แล้ว marshal ว่าแทนที่จะ searchresults struct ตัวเอง นี่คือตัวอย่างของวิธีที่คุณอาจกำหนดวิธีการดังกล่าว:

func fieldSet(fields ...string) map[string]bool {
    set := make(map[string]bool, len(fields))
    for _, s := range fields {
        set[s] = true
    }
    return set
}

func (s *SearchResult) SelectFields(fields ...string) map[string]interface{} {
    fs := fieldSet(fields...)
    rt, rv := reflect.TypeOf(*s), reflect.ValueOf(*s)
    out := make(map[string]interface{}, rt.NumField())
    for i := 0; i < rt.NumField(); i++ {
        field := rt.Field(i)
        jsonKey := field.Tag.Get("json")
        if fs[jsonKey] {
            out[jsonKey] = rv.Field(i).Interface()
        }
    }
    return out
}

และนี่คือวิธีแก้ปัญหาที่รันได้ซึ่งแสดงวิธีที่คุณจะเรียกวิธีนี้และจัดการตัวเลือกของคุณ: http://play.golang.org/p/1K9xjQRnO8


ลองคิดดูสิคุณสามารถสรุปรูปแบบ selectfields ให้เป็นประเภทใดก็ได้และคีย์แท็กใด ๆ ไม่มีอะไรเกี่ยวกับสิ่งนี้ที่เฉพาะเจาะจงกับคำจำกัดความ SearchResult หรือคีย์ json
jorelli

ฉันพยายามหลีกเลี่ยงการไตร่ตรอง แต่การบันทึกข้อมูลประเภทนี้ค่อนข้างดี ... เป็นเรื่องดีที่มีรหัสที่บันทึกว่าโครงสร้างของคุณมีลักษณะอย่างไรดีกว่ากลุ่มแท็ก if / else ในเมธอด validate () มีหนึ่ง)
Aktau

7

ฉันเพิ่งเผยแพร่นายอำเภอซึ่งเปลี่ยน structs ให้เป็นแผนที่โดยยึดตามแท็กที่ใส่หมายเหตุประกอบไว้ในเขตข้อมูล struct จากนั้นคุณสามารถ marshal (JSON หรืออื่น ๆ ) แผนที่ที่สร้างขึ้น อาจไม่อนุญาตให้คุณเรียงลำดับชุดเขตข้อมูลที่ผู้โทรขอเท่านั้น แต่ฉันคิดว่าการใช้กลุ่มชุดจะช่วยให้คุณครอบคลุมกรณีส่วนใหญ่ การใช้กลุ่มแทนเขตข้อมูลโดยตรงมักจะเพิ่มความสามารถในการแคช

ตัวอย่าง:

package main

import (
    "encoding/json"
    "fmt"
    "log"

    "github.com/hashicorp/go-version"
    "github.com/liip/sheriff"
)

type User struct {
    Username string   `json:"username" groups:"api"`
    Email    string   `json:"email" groups:"personal"`
    Name     string   `json:"name" groups:"api"`
    Roles    []string `json:"roles" groups:"api" since:"2"`
}

func main() {
    user := User{
        Username: "alice",
        Email:    "alice@example.org",
        Name:     "Alice",
        Roles:    []string{"user", "admin"},
    }

    v2, err := version.NewVersion("2.0.0")
    if err != nil {
        log.Panic(err)
    }

    o := &sheriff.Options{
        Groups:     []string{"api"},
        ApiVersion: v2,
    }

    data, err := sheriff.Marshal(o, user)
    if err != nil {
        log.Panic(err)
    }

    output, err := json.MarshalIndent(data, "", "  ")
    if err != nil {
        log.Panic(err)
    }
    fmt.Printf("%s", output)
}

7

ใช้สามส่วนผสม:

  1. reflectแพคเกจที่จะห่วงมากกว่าเขตทุกสมาชิกของโครงสร้าง

  2. ifคำสั่งให้รับเขตที่คุณต้องการMarshalและ

  3. encoding/jsonแพคเกจMarshalด้านของความชอบของคุณ

เตรียม:

  1. ผสมให้เข้ากันดี การใช้งานreflect.TypeOf(your_struct).Field(i).Name()ที่จะได้รับชื่อของที่iสนาม TH your_structของ

  2. การใช้งานreflect.ValueOf(your_struct).Field(i)ที่จะได้รับประเภทValueการเป็นตัวแทนของiเขต TH your_structของ

  3. ใช้fieldValue.Interface()เพื่อดึงมูลค่าที่แท้จริง (upcasted อินเตอร์เฟซประเภท {}) ของfieldValueชนิดValue(หมายเหตุการใช้วงเล็บ - อินเตอร์เฟซ () วิธีการผลิตinterface{}

หากคุณโชคดีที่ไม่ได้เผาทรานซิสเตอร์หรือเบรกเกอร์ใด ๆ ในกระบวนการคุณควรได้รับสิ่งนี้:

func MarshalOnlyFields(structa interface{},
    includeFields map[string]bool) (jsona []byte, status error) {
    value := reflect.ValueOf(structa)
    typa := reflect.TypeOf(structa)
    size := value.NumField()
    jsona = append(jsona, '{')
    for i := 0; i < size; i++ {
        structValue := value.Field(i)
        var fieldName string = typa.Field(i).Name
        if marshalledField, marshalStatus := json.Marshal((structValue).Interface()); marshalStatus != nil {
            return []byte{}, marshalStatus
        } else {
            if includeFields[fieldName] {
                jsona = append(jsona, '"')
                jsona = append(jsona, []byte(fieldName)...)
                jsona = append(jsona, '"')
                jsona = append(jsona, ':')
                jsona = append(jsona, (marshalledField)...)
                if i+1 != len(includeFields) {
                    jsona = append(jsona, ',')
                }
            }
        }
    }
    jsona = append(jsona, '}')
    return
}

ที่ให้บริการ:

ให้บริการกับโครงสร้างโดยพลการและmap[string]boolเขตข้อมูลที่คุณต้องการรวมตัวอย่างเช่น

type magic struct {
    Magic1 int
    Magic2 string
    Magic3 [2]int
}

func main() {
    var magic = magic{0, "tusia", [2]int{0, 1}}
    if json, status := MarshalOnlyFields(magic, map[string]bool{"Magic1": true}); status != nil {
        println("error")
    } else {
        fmt.Println(string(json))
    }

}

อร่อย!


คำเตือน! หาก includeFields ของคุณมีชื่อฟิลด์ซึ่งไม่ตรงกับฟิลด์จริงคุณจะได้รับ json ที่ไม่ถูกต้อง คุณได้รับการเตือน
Adam Kurkiewicz

5

คุณสามารถใช้แอตทริบิวต์การติดแท็ก "omitifempty" หรือทำตัวชี้ฟิลด์ที่เป็นตัวเลือกและปล่อยให้ผู้ที่คุณต้องการข้ามไม่มีการกำหนดค่าเริ่มต้น


นี่คือคำตอบที่ถูกต้องที่สุดสำหรับคำถาม OPs และกรณีการใช้งาน
user1943442

2
@ user1943442 ไม่ใช่ไม่ใช่ OP ระบุอย่างชัดเจนว่าทำไม "ละเว้น" จึงไม่เหมาะสม
Dave C

2

ฉันยังประสบปัญหานี้ในตอนแรกฉันแค่ต้องการตอบสนองในตัวจัดการ http ของฉัน วิธีแรกของฉันคือการสร้างแพ็คเกจที่คัดลอกข้อมูลของ struct ไปยังโครงสร้างอื่นแล้วจัดโครงสร้างที่สอง ฉันทำแพ็คเกจนั้นโดยใช้การสะท้อนดังนั้นไม่เคยชอบวิธีการแบบนั้นและฉันก็ไม่ได้เป็นแบบไดนามิก

ดังนั้นฉันจึงตัดสินใจแก้ไขแพ็คเกจการเข้ารหัส / json เพื่อทำสิ่งนี้ ฟังก์ชั่นMarshal, MarshalIndentและ(Encoder) Encodeนอกจากนี้ยังได้รับ

type F map[string]F

ฉันต้องการจำลอง JSON ของเขตข้อมูลที่จำเป็นในการจัดระเบียบดังนั้นจึงเป็นเพียงทุ่งที่อยู่ในแผนที่

https://github.com/JuanTorr/jsont

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/JuanTorr/jsont"
)

type SearchResult struct {
    Date        string      `json:"date"`
    IdCompany   int         `json:"idCompany"`
    Company     string      `json:"company"`
    IdIndustry  interface{} `json:"idIndustry"`
    Industry    string      `json:"industry"`
    IdContinent interface{} `json:"idContinent"`
    Continent   string      `json:"continent"`
    IdCountry   interface{} `json:"idCountry"`
    Country     string      `json:"country"`
    IdState     interface{} `json:"idState"`
    State       string      `json:"state"`
    IdCity      interface{} `json:"idCity"`
    City        string      `json:"city"`
} //SearchResult

type SearchResults struct {
    NumberResults int            `json:"numberResults"`
    Results       []SearchResult `json:"results"`
} //type SearchResults
func main() {
    msg := SearchResults{
        NumberResults: 2,
        Results: []SearchResult{
            {
                Date:        "12-12-12",
                IdCompany:   1,
                Company:     "alfa",
                IdIndustry:  1,
                Industry:    "IT",
                IdContinent: 1,
                Continent:   "america",
                IdCountry:   1,
                Country:     "México",
                IdState:     1,
                State:       "CDMX",
                IdCity:      1,
                City:        "Atz",
            },
            {
                Date:        "12-12-12",
                IdCompany:   2,
                Company:     "beta",
                IdIndustry:  1,
                Industry:    "IT",
                IdContinent: 1,
                Continent:   "america",
                IdCountry:   2,
                Country:     "USA",
                IdState:     2,
                State:       "TX",
                IdCity:      2,
                City:        "XYZ",
            },
        },
    }
    fmt.Println(msg)
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

        //{"numberResults":2,"results":[{"date":"12-12-12","idCompany":1,"idIndustry":1,"country":"México"},{"date":"12-12-12","idCompany":2,"idIndustry":1,"country":"USA"}]}
        err := jsont.NewEncoder(w).Encode(msg, jsont.F{
            "numberResults": nil,
            "results": jsont.F{
                "date":       nil,
                "idCompany":  nil,
                "idIndustry": nil,
                "country":    nil,
            },
        })
        if err != nil {
            log.Fatal(err)
        }
    })

    http.ListenAndServe(":3009", nil)
}

ฉันยังไม่ได้ลองเลย แต่มันก็ดูดี มันจะดียิ่งขึ้นถ้ารองรับอินเตอร์เฟสของ Marshaler ด้วยเช่นกัน
ฮักกี้

1

คำถามนี้ค่อนข้างเก่า แต่ฉันเจอปัญหาเดียวกันเมื่อไม่นานมานี้และเมื่อฉันพบวิธีที่ง่ายในการทำเช่นนี้ฉันได้สร้างห้องสมุดเพื่อเติมเต็มจุดประสงค์นี้ จะช่วยให้สร้างได้อย่างง่ายดายmap[string]interface{}จากโครงสร้างคงที่

https://github.com/tuvistavie/structomap


ตอนนี้คุณสามารถทำได้อย่างง่ายดายโดยใช้ข้อมูลโค้ดจากสูตรของฉัน
Adam Kurkiewicz

ตัวอย่างเป็นส่วนย่อยของห้องสมุด แต่ปัญหาสำคัญที่นี่เกี่ยวกับการส่งคืน[]byteคือมันไม่สามารถนำกลับมาใช้ใหม่ได้: ไม่มีวิธีง่ายๆในการเพิ่มเขตข้อมูลในภายหลัง ดังนั้นฉันขอแนะนำให้สร้างmap[string]interface{}และปล่อยให้ส่วนหนึ่งของการทำให้เป็นอันดับ JSON ไปยังไลบรารีมาตรฐาน
Daniel Perez

1

ฉันไม่ได้มีปัญหาเดียวกัน แต่คล้ายกัน โค้ดด้านล่างแก้ปัญหาของคุณได้เช่นกันแน่นอนถ้าคุณไม่คำนึงถึงปัญหาด้านประสิทธิภาพ ก่อนที่จะนำโซลูชันดังกล่าวไปใช้กับระบบของคุณฉันแนะนำให้คุณออกแบบโครงสร้างของคุณใหม่ถ้าทำได้ การส่งการตอบสนองโครงสร้างตัวแปรคือวิศวกรรมมากเกินไป ฉันเชื่อว่าโครงสร้างการตอบสนองแสดงถึงสัญญาระหว่างการร้องขอและทรัพยากรและไม่ควรขึ้นอยู่กับการร้องขอ (คุณสามารถทำให้เขตข้อมูลที่ไม่ต้องการเป็นโมฆะฉันทำ) ในบางกรณีเราต้องใช้การออกแบบนี้หากคุณเชื่อว่าคุณอยู่ในกรณีนั้นนี่คือลิงค์เล่นและรหัสที่ฉันใช้

type User2 struct {
    ID       int    `groups:"id" json:"id,omitempty"`
    Username string `groups:"username" json:"username,omitempty"`
    Nickname string `groups:"nickname" json:"nickname,omitempty"`
}

type User struct {
    ID       int    `groups:"private,public" json:"id,omitempty"`
    Username string `groups:"private" json:"username,omitempty"`
    Nickname string `groups:"public" json:"nickname,omitempty"`
}

var (
    tagName = "groups"
)

//OmitFields sets fields nil by checking their tag group value and access control tags(acTags)
func OmitFields(obj interface{}, acTags []string) {
    //nilV := reflect.Value{}
    sv := reflect.ValueOf(obj).Elem()
    st := sv.Type()
    if sv.Kind() == reflect.Struct {
        for i := 0; i < st.NumField(); i++ {
            fieldVal := sv.Field(i)
            if fieldVal.CanSet() {
                tagStr := st.Field(i).Tag.Get(tagName)
                if len(tagStr) == 0 {
                    continue
                }
                tagList := strings.Split(strings.Replace(tagStr, " ", "", -1), ",")
                //fmt.Println(tagList)
                // ContainsCommonItem checks whether there is at least one common item in arrays
                if !ContainsCommonItem(tagList, acTags) {
                    fieldVal.Set(reflect.Zero(fieldVal.Type()))
                }
            }
        }
    }
}

//ContainsCommonItem checks if arrays have at least one equal item
func ContainsCommonItem(arr1 []string, arr2 []string) bool {
    for i := 0; i < len(arr1); i++ {
        for j := 0; j < len(arr2); j++ {
            if arr1[i] == arr2[j] {
                return true
            }
        }
    }
    return false
}
func main() {
    u := User{ID: 1, Username: "very secret", Nickname: "hinzir"}
    //assume authenticated user doesn't has permission to access private fields
    OmitFields(&u, []string{"public"}) 
    bytes, _ := json.Marshal(&u)
    fmt.Println(string(bytes))


    u2 := User2{ID: 1, Username: "very secret", Nickname: "hinzir"}
    //you want to filter fields by field names
    OmitFields(&u2, []string{"id", "nickname"}) 
    bytes, _ = json.Marshal(&u2)
    fmt.Println(string(bytes))

}

1

ฉันสร้างฟังก์ชันนี้เพื่อแปลง struct เป็นสตริง JSON โดยไม่สนใจบางฟิลด์ หวังว่ามันจะช่วย

func GetJSONString(obj interface{}, ignoreFields ...string) (string, error) {
    toJson, err := json.Marshal(obj)
    if err != nil {
        return "", err
    }

    if len(ignoreFields) == 0 {
        return string(toJson), nil
    }

    toMap := map[string]interface{}{}
    json.Unmarshal([]byte(string(toJson)), &toMap)

    for _, field := range ignoreFields {
        delete(toMap, field)
    }

    toJson, err = json.Marshal(toMap)
    if err != nil {
        return "", err
    }
    return string(toJson), nil
}

ตัวอย่าง: https://play.golang.org/p/nmq7MFF47Gp


0

นี่คือวิธีที่ฉันกำหนดโครงสร้างของฉัน

type User struct {
    Username string  `json:"username" bson:"username"`
    Email    string  `json:"email" bson:"email"`
    Password *string `json:"password,omitempty" bson:"password"`
    FullName string  `json:"fullname" bson:"fullname"`
}

และภายในฟังก์ชั่นของฉันตั้งไว้user.Password = nilไม่ให้มาร์แชลล์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.