dongpao1083 2017-02-03 09:56
浏览 219
已采纳

自定义编组到bson和JSON(Golang和mgo)

I have the following type in Golang:

type Base64Data []byte

In order to support unmarshalling a base64 encoded string to this type, I did the following:

func (b *Base64Data) UnmarshalJSON(data []byte) error {
    if len(data) == 0 {
        return nil
    }

    content, err := base64.StdEncoding.DecodeString(string(data[1 : len(data)-1]))
    if err != nil {
        return err
    }

    *b = []byte(xml)
    return nil
}

Now I also want to be able to marshal and unmarshal it to mongo database, using mgo Golang library. The problem is that I already have documents there stored as base64 encoded string, so I have to maintain that. I tried to do the following:

func (b Base64Data) GetBSON() (interface{}, error) {
    return base64.StdEncoding.EncodeToString([]byte(b)), nil
}

func (b *Base64DecodedXml) SetBSON(raw bson.Raw) error {
    var s string
    var err error
    if err = raw.Unmarshal(&s); err != nil {
        return err
    }
    *b, err = base64.StdEncoding.DecodeString(s)
    return err
}

So that after unmarshaling, the data is already decoded, so I need to encode it back, and return it as a string so it will be written to db as a string (and vice versa) For that I implemented bson getter and setter, but it seems only the getter is working properly

JSON unmarshaling from base64 encoded string works, as well marshaling it to database. but unmarshling setter seems to not be called at all.

Can anyone suggest what I'm missing, so that I'll be able to properly hold the data decoded in memory, but encoded string type?

This is a test I tried to run:

b := struct {
    Value shared.Base64Data `json:"value" bson:"value"`
}{}
s := `{"value": "PHJvb3Q+aGVsbG88L3Jvb3Q+"}`
require.NoError(t, json.Unmarshal([]byte(s), &b))
t.Logf("%v", string(b.Value))
b4, err := bson.Marshal(b)
require.NoError(t, err)
t.Logf("%v", string(b4))
require.NoError(t, bson.Unmarshal(b4, &b))
t.Logf("%v", string(b.Value))
  • 写回答

1条回答 默认 最新

  • dongqing314511 2017-02-03 10:35
    关注

    You can't marshal any value with bson.Marshal(), only maps and struct values.

    If you want to test it, pass a map, e.g. bson.M to bson.Marshal():

    var x = Base64Data{0x01, 0x02, 0x03}
    
    dd, err := bson.Marshal(bson.M{"data": x})
    fmt.Println(string(dd), err)
    

    Your code works as-is, and as you intend it to. Try to insert a wrapper value to verify it:

    c := sess.DB("testdb").C("testcoll")
    
    var x = Base64Data{0x01, 0x02, 0x03}
    if err := c.Insert(bson.M{
        "data": x,
    }); err != nil {
        panic(err)
    }
    

    This will save the data as a string, being the Base64 encoded form.

    Of course if you want to load it back into a value of type Base64Data, you will also need to define the SetBSON(raw Raw) error method too (bson.Setter interface).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 虚拟机打包apk出现错误
  • ¥30 最小化遗憾贪心算法上界
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝