如何将Golang的big.Int存储到MongoDB中

3

我有一个结构体,其中引用了*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的包装器,实现MarshalBSONUnmarshalBSON(说实话,我甚至不确定如何正确地实现它)。但这将非常不方便。

2个回答

1
这是我想到的一种可能的实现方式,它将big.Int以纯文本形式存储到MongoDb中。也可以使用big.Int的BytesSetBytes方法将其轻松存储为字节数组,而不是使用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")
}

能否直接将 big.Int 转换为 string,并使用 MarshalBSON? - soulmachine

-3
当从结构体中获取数据时,该字段变为nil。
返回0的原因是big.Int没有可用的映射。如果您检查插入到MongoDB集合中的文档,应该会看到类似以下内容的东西:
{
  "_id": ObjectId("..."),
  "number": {}
}

number字段中没有存储值时。

如何将big.Int正确/最佳地存储到MongoDB中?

首先让我们了解一下BigInt是什么。大整数数据类型用于在整数值可能超过int数据类型支持的范围时使用。范围为-2^63(-9,223,372,036,854,775,808)至2^63-1(9,223,372,036,854,775,807),存储大小为8字节。通常在SQL中使用。

在Go中,您可以使用更精确的整数类型。可用的内置类型int8、int16、int32和int64(以及它们的无符号对应项)最适合数据。Go中大整数的对应项是int64。范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807,存储大小为8个字节。

使用mongo-go-driver,您只需使用int64,它将转换为bson RawValue.Int64。例如:

type MyStruct struct {
    Number  int64
}

collection := db.Collection("tests")
nb := MyStruct{Number: int64(42)}
r, _ := collection.InsertOne(context.TODO(), nb)

var result MyStruct
collection.FindOne(context.TODO(), bson.D{{"_id", r.InsertedID}}).Decode(&result)

big.Int 可以比 int64 更大。 - soulmachine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接