首页 > 解决方案 > 如何将 Golang big.Int 存储到 MongoDB 中

问题描述

我有一个引用 *big.Int 的结构。当将此结构天真地存储到 MongoDB 中(使用官方驱动程序)时,该字段在取回结构时变为 nil。将 big.Int 存储到 MongoDB 中的正确/最佳方法是什么?

    type MyStruct struct {
        Number *big.Int
    }

    nb := MyStruct{Number: big.NewInt(42)}
    r, _ := db.Collection("test").InsertOne(context.TODO(), nb)

    result := &MyStruct{}
    db.Collection("test").FindOne(context.TODO(), bson.D{{"_id", r.InsertedID}}).Decode(result)
    fmt.Println(result) // <== Number will be 0 here

到目前为止,我最好的想法是围绕 big.Int 创建一个实现MarshalBSONand的包装器UnmarshalBSON(老实说,我什至不知道如何正确地做到这一点)。但这会很不方便。

标签: mongodbgobigint

解决方案


这是我想出的一个可能的实现,它将 big.Int 作为纯文本存储到 MongoDb 中。也可以通过使用方法BytesSetBytesbig.Int 而不是MarshalText/轻松存储为字节数组UnmarshalText

package common

import (
    "fmt"
    "math/big"

    "go.mongodb.org/mongo-driver/bson"
)

type BigInt struct {
    i *big.Int
}

func NewBigInt(bigint *big.Int) *BigInt {
    return &BigInt{i: bigint}
}

func (bi *BigInt) Int() *big.Int {
    return bi.i
}
func (bi *BigInt) MarshalBSON() ([]byte, error) {
    txt, err := bi.i.MarshalText()
    if err != nil {
        return nil, err
    }
    a, err := bson.Marshal(map[string]string{"i": string(txt)})
    return a, err
}

func (bi *BigInt) UnmarshalBSON(data []byte) error {
    var d bson.D
    err := bson.Unmarshal(data, &d)
    if err != nil {
        return err
    }
    if v, ok := d.Map()["i"]; ok {
        bi.i = big.NewInt(0)
        return bi.i.UnmarshalText([]byte(v.(string)))
    }
    return fmt.Errorf("key 'i' missing")
}

推荐阅读