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 平板录音机录音问题解决
  • ¥15 请问维特智能的安卓APP在手机上存储传感器数据后,如何找到它的存储路径?
  • ¥15 (SQL语句|查询结果翻了4倍)
  • ¥15 Odoo17操作下面代码的模块时出现没有'读取'来访问
  • ¥50 .net core 并发调用接口问题
  • ¥15 网上各种方法试过了,pip还是无法使用
  • ¥15 用verilog实现tanh函数和softplus函数
  • ¥15 Hadoop集群部署启动Hadoop时碰到问题
  • ¥15 求京东批量付款能替代天诚
  • ¥15 slaris 系统断电后,重新开机后一直自动重启