I’m using golang mongo driver to get data from mongodb, I have a field that sometimes can be a string, bool… so I need to write a custom type to parse it into int64 when read from database, here is example code:
type Product struct {
Id string `json:"id" bson:"_id"`
TotalForSell *DBInt64 `json:"total_for_sell" bson:"total_for_sell,omitempty"`
}
type DBInt64 int64
func (i DBInt64) MarshalBSONValue() (bsontype.Type, []byte, error) {
return bson.MarshalValue(int64(i))
}
func (i *DBInt64) UnmarshalBSONValue(t bsontype.Type, value []byte) error {
switch t {
case bson.TypeInt32:
intValue, _, ok := bsoncore.ReadInt32(value)
if !ok {
return fmt.Errorf("failed to read BSON int32")
}
*i = DBInt64(intValue)
case bson.TypeInt64:
intValue, _, ok := bsoncore.ReadInt64(value)
if !ok {
return fmt.Errorf("failed to read BSON int64")
}
*i = DBInt64(intValue)
case bson.TypeString:
s, _, ok := bsoncore.ReadString(value)
if !ok {
return fmt.Errorf("failed to read BSON string")
}
if utils.IsEmptyString(&s) {
*i = DBInt64(0)
break
}
ret, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return fmt.Errorf("failed to convert BSON string to int64: %s", err.Error())
}
*i = DBInt64(ret)
case bson.TypeDouble:
floatValue, _, ok := bsoncore.ReadDouble(value)
if !ok {
return fmt.Errorf("failed to read BSON float64")
}
*i = DBInt64(floatValue)
default:
*i = DBInt64(0)
}
return nil
}
```
When field ` total_for_sale` was set to `null` in database, I still get 0 in Product struct, my expect is to get `nil` instead, but when I changed type `TotalForSell` to *int64, I can get `nil` as normal, but it cannot parse empty string or bool any more (it will get error if value in database is string or bool, how can I deal with null when I using custom type? I want to get null intead zero values of custom type
Here is my specifications:
- golang: v1.23
- mongo-driver v1.17.1
Thank you
Sorry, I cant edit the post so I append my issue and expectation here:
When field total_for_sale
was set to null
in database, I still get 0 in Product struct, my expect is to get nil
instead, but when I change type TotalForSell
to *int64
, I can get nil
as normal, but it cannot parse empty string or bool any more (it will get error if value in database is string or bool, how can I deal with null when I using custom type? I want to get null intead zero values of custom type
Here is my specifications:
- golang: v1.23
- mongo-driver v1.17.1
Thank you
@Chung_Hoang_Van Your decoder makes the default zero. You need to add a case for bsontype.Null
. Optionally, you can deal with this after decoding using the bson.RawValue
API:
type Product struct {
Id string `json:"id" bson:"_id"`
TotalForSellRawValue bson.RawValue `json:"total_for_sell" bson:"total_for_sell,omitempty"`
}
func (product *Product) TotalForSell() int64 {
switch product.TotalForSellRawValue.Type {
case bson.TypeInt64:
return product.TotalForSellRawValue.Int64()
}
return 0
}
@Preston_Vasquez
Thank you for your reply, I added a case for type Null like below but still got 0
instead nil
Is there another way to get nil and not use bson.RawValue
?
switch t {
case bson.TypeInt32:
intValue, _, ok := bsoncore.ReadInt32(value)
if !ok {
return fmt.Errorf("failed to read BSON int32")
}
*i = DBInt64(intValue)
case bson.TypeInt64:
intValue, _, ok := bsoncore.ReadInt64(value)
if !ok {
return fmt.Errorf("failed to read BSON int64")
}
*i = DBInt64(intValue)
case bson.TypeString:
s, _, ok := bsoncore.ReadString(value)
if !ok {
return fmt.Errorf("failed to read BSON string")
}
if utils.IsEmptyString(&s) {
*i = DBInt64(0)
break
}
ret, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return fmt.Errorf("failed to convert BSON string to int64: %s", err.Error())
}
*i = DBInt64(ret)
case bson.TypeDouble:
floatValue, _, ok := bsoncore.ReadDouble(value)
if !ok {
return fmt.Errorf("failed to read BSON float64")
}
*i = DBInt64(floatValue)
case bson.TypeNull:
return nil
default:
*i = DBInt64(0)
}
return nil
}
@Chung_Hoang_Van I see what you mean, I think this is a bug in the Go Driver. I’ve opened GODRIVER-3436 for further investigation.
Thank you, I will follow ticket to upgrade version when it ready