处理自定义BSON封送处理

处理自定义BSON封送处理

问题描述:

I have a number of structs that require custom marshalling. When I was testing I was using JSON and the standard JSON marshaller. As it doesn't marshal unexported fields, I needed to write a custom MarshalJSON function, which worked perfectly. When I called json.Marshal on the parent struct containing the ones that needed custom marshalling as fields, it worked fine.

Now I need to marshal everything to BSON for some MongoDB work, and I can't find any documentation about how to write custom BSON marshalling. Can anyone tell me how to do the equivalent for BSON/mgo for what I've demonstrated below?

currency.go (the important parts)

type Currency struct {
    value        decimal.Decimal //The actual value of the currency.
    currencyCode string          //The ISO currency code.
}

/*
MarshalJSON implements json.Marshaller.
*/
func (c Currency) MarshalJSON() ([]byte, error) {
    f, _ := c.Value().Float64()
    return json.Marshal(struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    }{
        Value:        f,
        CurrencyCode: c.CurrencyCode(),
    })
}

/*
UnmarshalJSON implements json.Unmarshaller.
*/
func (c *Currency) UnmarshalJSON(b []byte) error {

    decoded := new(struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    })

    jsonErr := json.Unmarshal(b, decoded)

    if jsonErr == nil {
        c.value = decimal.NewFromFloat(decoded.Value)
        c.currencyCode = decoded.CurrencyCode
        return nil
    } else {
        return jsonErr
    }
}

product.go (again, just the relevant parts)

type Product struct {
    Name  string
    Code  string
    Price currency.Currency
}

When I call json.Marshal(p) where p is a Product, it produces the output I want without the need for the pattern (not sure of the name) where you create a struct which is just a clone with all exported fields.

In my opinion using the inline method I've used greatly simplifies the API and stops you having extra structs that clutter things up.

我有许多需要自定义编组的结构。 在测试时,我使用的是JSON和标准的JSON marshaller。 由于它不会封送未导出的字段,因此我需要编写一个自定义的MarshalJSON函数,该函数运行良好。 当我在包含需要自定义编组的字段的父结构上调用json.Marshal时,它工作正常。 p>

现在,我需要将所有内容封送给BSON进行MongoDB的工作,我 找不到有关如何编写自定义BSON编组的任何文档。 谁能告诉我如何针对BSON / mgo做与我下面演示的等效的操作? p>

currency.go strong>(重要部分) p >

  type货币结构{
值十进制。十进制//货币的实际值。
 currencyCode字符串// ISO货币代码。
} 
 
 / *  
MarshalJSON实现json.Marshaller。
 * / 
func(c货币)MarshalJSON()([] byte,error){
f,_:= c.Value()。Float64()
返回json.Marshal(  struct {
 Value float64`json:“ value” bson:“ value”`
 CurrencyCode字符串`json:“ currencyCode” bson:“ currencyCode”`
} {
值:f,
 CurrencyCode:c。  CurrencyCode(),
}} 
} 
 
 / * 
UnmarshalJSON实现json.Unmarshaller。
 * / 
func(c * Currency)UnmarshalJSON(b [] byte)错误{
 
解码:  = new(结构{
 Value float64`json:“ value” bson:“ value”`
 CurrencyCode字符串`json:“ currencyCode” bson:“ currencyCode”`
})
 
 jsonErr  := json.Unmarshal(b,已解码)
 
,如果jsonErr == nil {
 c.value =十进制.NewFromFloat(decoded.Value)
 c.currencyCode =已解码.CurrencyCode 
返回nil 
} 否则{
返回jsonErr 
} 
} 
  code>  pre> 
 
 

product.go strong>(同样,只是相关部分) p >

  type产品结构{
名称字符串
代码字符串
价格货币。货币
} 
  code>  pre> 
 
 

何时 我叫json.Marshal(p),其中p是一个Product,它将在不需要模式(不确定名称)的情况下生成我想要的输出,在此模式下您将创建一个结构,该结构只是具有所有导出字段的克隆。 p>

我认为我使用的内联方法大大简化了API,并阻止了您使用多余的结构使事情变得混乱。 p> div>

Custom bson Marshalling/Unmarshalling works nearly the same way, you have to implement the Getter and Setter interfaces respectively

Something like this should work :

type Currency struct {
    value        decimal.Decimal //The actual value of the currency.
    currencyCode string          //The ISO currency code.
}

// GetBSON implements bson.Getter.
func (c Currency) GetBSON() (interface{}, error) {
    f := c.Value().Float64()
    return struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    }{
        Value:        f,
        CurrencyCode: c.currencyCode,
    }, nil
}

// SetBSON implements bson.Setter.
func (c *Currency) SetBSON(raw bson.Raw) error {

    decoded := new(struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    })

    bsonErr := raw.Unmarshal(decoded)

    if bsonErr == nil {
        c.value = decimal.NewFromFloat(decoded.Value)
        c.currencyCode = decoded.CurrencyCode
        return nil
    } else {
        return bsonErr
    }
}