MongoDB Golang driver custom type with pointer issue

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