处理自定义的BSON编组

huangapple go评论122阅读模式
英文:

Handling Custom BSON Marshaling

问题

我有一些需要自定义编组的结构体。在测试时,我使用了 JSON 和标准的 JSON 编组器。由于它不会编组未公开的字段,所以我需要编写一个自定义的 MarshalJSON 函数,这个函数运行得很好。当我对包含需要自定义编组的字段的父结构体调用 json.Marshal 时,它也能正常工作。

现在,我需要将所有内容编组为 BSON,用于一些 MongoDB 的工作,但我找不到关于如何编写自定义 BSON 编组的文档。有人可以告诉我如何为 BSON/mgo 编写与下面所示相同的代码吗?

currency.go(重要部分)

  1. type Currency struct {
  2. value decimal.Decimal // 货币的实际值。
  3. currencyCode string // ISO 货币代码。
  4. }
  5. /*
  6. MarshalJSON 实现了 json.Marshaller 接口。
  7. */
  8. func (c Currency) MarshalJSON() ([]byte, error) {
  9. f, _ := c.Value().Float64()
  10. return json.Marshal(struct {
  11. Value float64 `json:"value" bson:"value"`
  12. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  13. }{
  14. Value: f,
  15. CurrencyCode: c.CurrencyCode(),
  16. })
  17. }
  18. /*
  19. UnmarshalJSON 实现了 json.Unmarshaller 接口。
  20. */
  21. func (c *Currency) UnmarshalJSON(b []byte) error {
  22. decoded := new(struct {
  23. Value float64 `json:"value" bson:"value"`
  24. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  25. })
  26. jsonErr := json.Unmarshal(b, decoded)
  27. if jsonErr == nil {
  28. c.value = decimal.NewFromFloat(decoded.Value)
  29. c.currencyCode = decoded.CurrencyCode
  30. return nil
  31. } else {
  32. return jsonErr
  33. }
  34. }

product.go(同样,只包含相关部分)

  1. type Product struct {
  2. Name string
  3. Code string
  4. Price currency.Currency
  5. }

当我调用 json.Marshal(p),其中 p 是一个 Product,它会产生我想要的输出,而无需使用克隆所有公开字段的结构体的模式(不确定名称)。

在我看来,使用我所使用的内联方法极大地简化了 API,并且避免了使事情变得混乱的额外结构体。

英文:

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)

  1. type Currency struct {
  2. value decimal.Decimal //The actual value of the currency.
  3. currencyCode string //The ISO currency code.
  4. }
  5. /*
  6. MarshalJSON implements json.Marshaller.
  7. */
  8. func (c Currency) MarshalJSON() ([]byte, error) {
  9. f, _ := c.Value().Float64()
  10. return json.Marshal(struct {
  11. Value float64 `json:"value" bson:"value"`
  12. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  13. }{
  14. Value: f,
  15. CurrencyCode: c.CurrencyCode(),
  16. })
  17. }
  18. /*
  19. UnmarshalJSON implements json.Unmarshaller.
  20. */
  21. func (c *Currency) UnmarshalJSON(b []byte) error {
  22. decoded := new(struct {
  23. Value float64 `json:"value" bson:"value"`
  24. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  25. })
  26. jsonErr := json.Unmarshal(b, decoded)
  27. if jsonErr == nil {
  28. c.value = decimal.NewFromFloat(decoded.Value)
  29. c.currencyCode = decoded.CurrencyCode
  30. return nil
  31. } else {
  32. return jsonErr
  33. }
  34. }

product.go (again, just the relevant parts)

  1. type Product struct {
  2. Name string
  3. Code string
  4. Price currency.Currency
  5. }

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.

答案1

得分: 23

自定义的bson编组/解组几乎以相同的方式进行,您需要分别实现GetterSetter接口。

类似这样的代码应该可以工作:

  1. type Currency struct {
  2. value decimal.Decimal // 货币的实际值。
  3. currencyCode string // ISO货币代码。
  4. }
  5. // GetBSON 实现了bson.Getter接口。
  6. func (c Currency) GetBSON() (interface{}, error) {
  7. f := c.Value().Float64()
  8. return struct {
  9. Value float64 `json:"value" bson:"value"`
  10. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  11. }{
  12. Value: f,
  13. CurrencyCode: c.currencyCode,
  14. }, nil
  15. }
  16. // SetBSON 实现了bson.Setter接口。
  17. func (c *Currency) SetBSON(raw bson.Raw) error {
  18. decoded := new(struct {
  19. Value float64 `json:"value" bson:"value"`
  20. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  21. })
  22. bsonErr := raw.Unmarshal(decoded)
  23. if bsonErr == nil {
  24. c.value = decimal.NewFromFloat(decoded.Value)
  25. c.currencyCode = decoded.CurrencyCode
  26. return nil
  27. } else {
  28. return bsonErr
  29. }
  30. }
英文:

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

Something like this should work :

  1. type Currency struct {
  2. value decimal.Decimal //The actual value of the currency.
  3. currencyCode string //The ISO currency code.
  4. }
  5. // GetBSON implements bson.Getter.
  6. func (c Currency) GetBSON() (interface{}, error) {
  7. f := c.Value().Float64()
  8. return struct {
  9. Value float64 `json:"value" bson:"value"`
  10. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  11. }{
  12. Value: f,
  13. CurrencyCode: c.currencyCode,
  14. }, nil
  15. }
  16. // SetBSON implements bson.Setter.
  17. func (c *Currency) SetBSON(raw bson.Raw) error {
  18. decoded := new(struct {
  19. Value float64 `json:"value" bson:"value"`
  20. CurrencyCode string `json:"currencyCode" bson:"currencyCode"`
  21. })
  22. bsonErr := raw.Unmarshal(decoded)
  23. if bsonErr == nil {
  24. c.value = decimal.NewFromFloat(decoded.Value)
  25. c.currencyCode = decoded.CurrencyCode
  26. return nil
  27. } else {
  28. return bsonErr
  29. }
  30. }

huangapple
  • 本文由 发表于 2015年6月17日 20:14:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/30891301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定