使用 mongo-driver 自定义 BSON 编组和解组

我有一个像下面这样的结构字段。我还将相同结构的原始 protobuf 存储在 db 中。现在每次都将数据获取或保存到 mongo。ReallyBigRaw当我想保存到数据库时,我必须从 proto更新,而当我必须解组ReallyBigRaw以ReallyBigObj给出响应时,我必须解组。有没有办法我可以实现一些接口或提供一些回调函数,以便 mongo 驱动程序在保存或从 DB 获取数据之前自动执行此操作。


另外,我没有使用官方的 golang mongo 驱动程序mgo,我已经阅读了一些可以在mgogolang 库中完成的答案。


import (

    "github.com/golang/protobuf/jsonpb"

    "go.mongodb.org/mongo-driver/bson"

    "go.mongodb.org/mongo-driver/bson/primitive"


    proto "github.com/dinesh/api/go"

)


type ReallyBig struct {

    ID           string                 `bson:"_id,omitempty"`

    DraftID      string                 `bson:"draft_id,omitempty"`

// Marshaled ReallyBigObj proto to map[string]interface{} stored in DB

    ReallyBigRaw map[string]interface{} `bson:"raw,omitempty"`

    ReallyBigObj *proto.ReallyBig       `bson:"-"`

    CreatedAt    primitive.DateTime     `bson:"created_at,omitempty"`

    UpdatedAt    primitive.DateTime     `bson:"updated_at,omitempty"`

}


func (r *ReallyBig) GetProto() (*proto.ReallyBig, error) {

    if r.ReallyBigObj != nil {

        return r.ReallyBigObj, nil

    }

    Obj, err := getProto(r.ReallyBigRaw)

    if err != nil {

        return nil, err

    }

    r.ReallyBigObj = Obj

    return r.ReallyBigObj, nil

}


func getRaw(r *proto.ReallyBig) (map[string]interface{}, error) {

    m := jsonpb.Marshaler{}

    b := bytes.NewBuffer([]byte{})


    // marshals proto to json format

    err := m.Marshal(b, r)

    if err != nil {

        return nil, err

    }

    var raw map[string]interface{}

    // unmarshal the raw data to an interface

    err = json.Unmarshal(b.Bytes(), &raw)

    if err != nil {

        return nil, err

    }

    return raw, nil

}


func getProto(raw map[string]interface{}) (*proto.ReallyBig, error) {

    b, err := json.Marshal(raw)

    if err != nil {

        return nil, err

    }

    u := jsonpb.Unmarshaler{}

    var reallyBigProto proto.ReallyBig

    err = u.Unmarshal(bytes.NewReader(b), &recipeProto)

    if err != nil {

        return nil, err

    }

    return &reallyBigProto, nil

}


富国沪深
浏览 149回答 1
1回答

繁星coding

我实现了MarshalerandUnmarshaler接口。由于 mongo 驱动程序调用MarshalBSON并且UnmarshalBSON如果类型实现Marshaler并且Unmarshaler我们也最终陷入无限循环。为了避免这种情况,我们创建了type. 别名Golang仅继承字段而不是方法,因此我们最终调用正常bson.Marshal和bson.Unmarshalfunc (r *ReallyBig) MarshalBSON() ([]byte, error) {    type ReallyBigAlias ReallyBig    reallyBigRaw, err := getRaw(r.ReallyBigObj)    if err != nil {        return nil, err    }    r.ReallyBigRaw = reallyBigRaw    return bson.Marshal((*ReallyBigAlias)(r))}func (r *ReallyBig) UnmarshalBSON(data []byte) error {    type ReallyBigAlias ReallyBig    err := bson.Unmarshal(data, (*ReallyBigAlias)(r))    if err != nil {        return err    }    reallyBigProto, err := getProto(r.ReallyBigRaw)    if err != nil {        return err    }    r.ReallyBigObj = reallyBigProto    return nil}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go