为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
富国沪深 2022-07-11 16:28:21
我有一个像下面这样的结构字段。我还将相同结构的原始 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}
查看完整描述

1 回答

?
繁星coding

TA贡献1797条经验 获得超4个赞

我实现了MarshalerandUnmarshaler接口。由于 mongo 驱动程序调用MarshalBSON并且UnmarshalBSON如果类型实现Marshaler并且Unmarshaler我们也最终陷入无限循环。为了避免这种情况,我们创建了type. 别名Golang仅继承字段而不是方法,因此我们最终调用正常bson.Marshal和bson.Unmarshal


func (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

}


查看完整回答
反对 回复 2022-07-11
  • 1 回答
  • 0 关注
  • 148 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信