第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

Go + MongoDB:多態(tài)查詢

Go + MongoDB:多態(tài)查詢

Go
慕的地8271018 2023-06-12 14:24:03
我將 Go 和 MongoDB 與 mgo 驅(qū)動(dòng)程序一起使用。我試圖在同一個(gè) MongoDB 集合中保留和檢索不同的結(jié)構(gòu)(實(shí)現(xiàn)通用接口)。我來自 Java 世界(使用 Spring 很容易做到這一點(diǎn),幾乎沒有配置),但我很難用 Go 做類似的事情。這是我用于測試的簡化設(shè)置。假設(shè)兩個(gè)結(jié)構(gòu)S1andS2實(shí)現(xiàn)了一個(gè)公共接口I。S2有一個(gè)類型的隱式字段S1,這意味著在結(jié)構(gòu)方面S2嵌入了一個(gè)S1值,并且在類型方面S2實(shí)現(xiàn)了I。type I interface {    f1()}type S1 struct {    X int}type S2 struct {    S1    Y int}func (*S1) f1() {    fmt.Println("f1")}S1現(xiàn)在我可以保存or的實(shí)例并S2輕松使用mgo.Collection.Insert(),但是為了正確填充一個(gè)值 usingmgo.Collection.Find().One()例如,我需要傳遞一個(gè)指向S1or的現(xiàn)有值的指針S2,這意味著我已經(jīng)知道我想要讀取的對象的類型?。∥蚁M軌驈?MongoDB 集合中檢索文檔,而不知道它是S1、還是S2,或者實(shí)際上是實(shí)現(xiàn)I.這是我到目前為止的位置:我沒有直接保存我想要保留的對象,而是保存了一個(gè)Wrapper包含 MongoDB id、類型標(biāo)識(shí)符和實(shí)際值的結(jié)構(gòu)。類型標(biāo)識(shí)符是packageName + "."的串聯(lián)。+ typeName,它用于在類型注冊表中查找類型,因?yàn)樵?Go 中沒有從類型名稱映射到 Type 對象的本地機(jī)制。這意味著我需要注冊我希望能夠保留和檢索的類型,但我可以接受。事情是這樣的:typeregistry.Register(reflect.TypeOf((*S1)(nil)).Elem())typeregistry.Register(reflect.TypeOf((*S2)(nil)).Elem())這是類型注冊表的代碼:var types map[string]reflect.Typefunc init() {    types = make(map[string]reflect.Type)}func Register(t reflect.Type) {    key := GetKey(t)    types[key] = t}func GetKey(t reflect.Type) string {    key := t.PkgPath() + "." + t.Name()    return key}func GetType(key string) reflect.Type {    t := types[key]    return t}保存對象的代碼非常簡單:func save(coll *mgo.Collection, s I) (bson.ObjectId, error) {    t := reflect.TypeOf(s)    wrapper := Wrapper{        Id:      bson.NewObjectId(),        TypeKey: typeregistry.GetKey(t),        Val:     s,    }    return wrapper.Id, coll.Insert(wrapper)}檢索對象的代碼有點(diǎn)棘手:func getById(coll *mgo.Collection, id interface{}) (*I, error) {    // read wrapper    wrapper := Wrapper{}    err := coll.Find(bson.M{"_id": id}).One(&wrapper)    if err != nil {        return nil, err    }}這在返回的對象類型正確時(shí)部分起作用,但我無法弄清楚的是如何使用pt從 MongoDB 檢索的數(shù)據(jù)填充值,這些數(shù)據(jù)存儲(chǔ)wrapper.Val為bson.M.所以基本上剩下的問題是:如何從bson.M值填充未知結(jié)構(gòu)?我確定必須有一個(gè)簡單的解決方案......在此先感謝您的幫助。這是包含所有代碼的 Github 要點(diǎn):https://gist.github.com/ogerardin/5aa272f69563475ba9d7b3194b12ae57
查看完整描述

2 回答

?
江戶川亂折騰

TA貢獻(xiàn)1851條經(jīng)驗(yàn) 獲得超5個(gè)贊

首先,您應(yīng)該始終檢查返回的錯(cuò)誤。bson.Marshal()bson.Unmarshal()返回您不檢查的錯(cuò)誤。這樣做揭示了為什么它不起作用:

unmarshal 無法處理結(jié)構(gòu)值。使用指針

pt是類型reflect.Value(恰好是一個(gè)結(jié)構(gòu)),而不是你應(yīng)該傳遞給bson.Unmarshal().?例如,您應(yīng)該傳遞一個(gè)指向要解組的結(jié)構(gòu)值的指針(它將被包裝在一個(gè)interface{}值中)。所以調(diào)用Value.Interface()返回的值reflect.New()

pt?:=?reflect.New(t).Interface()

您可以將其傳遞給bson.Unmarshal()

bsonBytes, err := bson.Marshal(m)

if err != nil {

? ? panic(err)

}

if err = bson.Unmarshal(bsonBytes, pt); err != nil {

? ? panic(err)

}

(在你的真實(shí)代碼中你想做一些除了 panic 之外的事情,這只是為了表明你應(yīng)該總是檢查錯(cuò)誤?。?/p>

另請注意,可以將映射直接轉(zhuǎn)換為結(jié)構(gòu)(直接意味著無需編組和解組)。您可以手動(dòng)實(shí)施或使用現(xiàn)成的第 3 方庫。

另請注意,有更聰明的方法可以解決您想要做的事情。您可以將類型存儲(chǔ)在 ID 本身中,因此如果您有 ID,則可以構(gòu)造一個(gè)類型的值以解組到查詢結(jié)果中,這樣您就可以跳過整個(gè)過程。這會(huì)簡單得多,效率也高得多。

例如,您可以使用以下 ID 結(jié)構(gòu):

<type>-<id>

例如:

my.package.S1-123

獲取/加載此文檔時(shí),您可以使用反射來創(chuàng)建 的值my.package.S1,并直接解組到該值(將其傳遞給Query.One())。


查看完整回答
反對 回復(fù) 2023-06-12
?
森欄

TA貢獻(xiàn)1810條經(jīng)驗(yàn) 獲得超5個(gè)贊

這是一個(gè)getById()實(shí)際有效的修改版本:


func getById(coll *mgo.Collection, id interface{}) (*I, error) {

? ? // read wrapper

? ? wrapper := Wrapper{}

? ? err := coll.Find(bson.M{"_id": id}).One(&wrapper)

? ? if err != nil {

? ? ? ? return nil, err

? ? }


? ? // obtain Type from registry

? ? t := typeregistry.GetType(wrapper.TypeKey)


? ? // get a pointer to a new value of this type

? ? pt := reflect.New(t)


? ? // populate value using wrapper.Val

? ? err = mapstructure.Decode(wrapper.V, pt.Interface())

? ? if err != nil {

? ? ? ? return nil, err

? ? }


? ? // return the value as *I

? ? i := pt.Elem().Interface().(I)

? ? return &i, nil

}

從結(jié)構(gòu)到結(jié)構(gòu)的轉(zhuǎn)換由https://github.com/mitchellh/mapstructurebson.M處理,而不是 marshalling-unmarshaling。


查看完整回答
反對 回復(fù) 2023-06-12
  • 2 回答
  • 0 關(guān)注
  • 210 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)