你的mongoDB也要和decimal组CP

众所周知,浮点数是很调皮的

都谁在说,喜欢技术八卦的你,不可以错过
浮点计算引发的血案
Go如何精确计算小数-Decimal研究-Tidb MyDecimal问题

而mongodb/mongo-go-driver中的bson.Decimal128只顾及自家存储的一亩三分地,看起来干干巴巴、麻麻赖赖…… 大家先不着急盘它,据说有个俊俏的 github.com/shopspring/decimal,咱们可以说个媒。

// 我希望mongo中,读取数据时decimal类型直接解析到decimal.Decimal中
// 写入时,又直接把decimal.Decimal放入到mongo的decimal类型中
type Model struct {
  // 这个VIP积分非常重要,弄错公司就玩完啦~
  // 只有他才配的上 decimal.Decimal (狗头
  VIPScore decimal.Decimal `bson:"vip_score"`
}

这回文档有点不好使啦,只能用google到处搜,到处搜

package mongo

import (
    "fmt"
    "reflect"

    "github.com/shopspring/decimal"
    "go.mongodb.org/mongo-driver/bson/bsoncodec"
    "go.mongodb.org/mongo-driver/bson/bsonrw"
    "go.mongodb.org/mongo-driver/bson/bsontype"
    "go.mongodb.org/mongo-driver/bson/primitive"
)

type Decimal decimal.Decimal

func (d Decimal) DecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
    decimalType := reflect.TypeOf(decimal.Decimal{})
    if !val.IsValid() || !val.CanSet() || val.Type() != decimalType {
        return bsoncodec.ValueDecoderError{
            Name:     "decimalDecodeValue",
            Types:    []reflect.Type{decimalType},
            Received: val,
        }
    }

    var value decimal.Decimal
    switch vr.Type() {
    case bsontype.Decimal128:
        dec, err := vr.ReadDecimal128()
        if err != nil {
            return err
        }
        value, err = decimal.NewFromString(dec.String())
        if err != nil {
            return err
        }
    default:
        return fmt.Errorf("received invalid BSON type to decode into decimal.Decimal: %s", vr.Type())
    }

    val.Set(reflect.ValueOf(value))
    return nil
}

func (d Decimal) EncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
    decimalType := reflect.TypeOf(decimal.Decimal{})
    if !val.IsValid() || val.Type() != decimalType {
        return bsoncodec.ValueEncoderError{
            Name:     "decimalEncodeValue",
            Types:    []reflect.Type{decimalType},
            Received: val,
        }
    }

    dec := val.Interface().(decimal.Decimal)
    dec128, err := primitive.ParseDecimal128(dec.String())
    if err != nil {
        return err
    }

    return vw.WriteDecimal128(dec128)
}

然后呢,需要到ClientOptions注册自定义编码解码

     cli, err := mongo.NewClient(options.Client().ApplyURI("这是个mongoURI连接地址").
            SetRegistry(bson.NewRegistryBuilder().
                RegisterDecoder(reflect.TypeOf(decimal.Decimal{}), Decimal{}).
                RegisterEncoder(reflect.TypeOf(decimal.Decimal{}), Decimal{}).
                Build())
    if err != nil {
        log.Fatal().Err(err).Msg("连接到mongo")
    }

大概就是这样。

另外,我想帮一个朋友问问mongo的接口怎这么费眼睛呢?

你可能感兴趣的:(你的mongoDB也要和decimal组CP)