为了账号安全,请及时绑定邮箱和手机立即绑定

为什么 json.RawMessage 会放大 mongoDb 文档大小?

为什么 json.RawMessage 会放大 mongoDb 文档大小?

Go
长风秋雁 2023-07-31 10:45:14
以下代码尝试通过以下方式将新文档插入到 mongoDB 中go.mongodb.org/mongo-driver    data := "this is test string blablablablablablabla"    type Doc struct {        Version int "json:version, bson:version"        Data   string   "json:data, bson:data"    }    dd := Doc{Version: 21, Data: data}    dObj, _ := json.Marshal(dd)    queryFilter := bson.M{"version": 1}    update1 := bson.M{"$set": bson.M{"version": 1, "data": json.RawMessage(dObj)}}    // insert data with json.RawMessage    _, err := db.Mongo("test").Collection("test_doc1").UpdateOne(context.Background(), queryFilter, update1, options.Update().SetUpsert(true))    if err != nil {        fmt.Println("failed to insert doc1")    }    update2 := bson.M{"$set": bson.M{"version": 1, "data": (dObj)}}    // insert data without json.RawMessage    _, err = db.Mongo("test").Collection("test_doc2").UpdateOne(context.Background(), queryFilter, update2, options.Update().SetUpsert(true))    if err != nil {        fmt.Println("failed to insert doc2")    }的内容test_doc1是"data": json.RawMessage(dObj),而 的内容test_doc2是"data": (dObj)。文档内容如下db.test_doc1.find(){ "_id" : ObjectId("5da164a950d625a5b2e5d23e"), "version" : 1, "data" : [ 123, 34, 86, 101, 114, 115, 105, 111, 110, 34, 58, 50, 49, 44, 34, 68, 97, 116, 97, 34, 58, 34, 116, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103, 32, 98, 108, 97, 98, 108, 97, 98, 108, 97, 98, 108, 97, 98, 108, 97, 98, 108, 97, 98, 108, 97, 34, 125 ] }db.test_doc2.find(){ "_id" : ObjectId("5da164a950d625a5b2e5d249"), "version" : 1, "data" : BinData(0,"eyJWZXJzaW9uIjoyMSwiRGF0YSI6InRoaXMgaXMgdGVzdCBzdHJpbmcgYmxhYmxhYmxhYmxhYmxhYmxhYmxhIn0=") }检查以上两个文件的大小后Object.bsonsize(db.test_doc2.findOne())111Object.bsonsize(db.test_doc1.findOne())556的尺寸test_doc1比 的尺寸更大test_doc2。为什么?每个bson 文档数组 - 数组的文档是一个普通的 BSON 文档,其键为整数值,从 0 开始并按顺序继续。例如,数组 ['red', 'blue'] 将被编码为文档 {'0': 'red', '1': 'blue'}。键必须按数字升序排列。Bson数组可以占用更多的磁盘空间吗?我对吗?MongoDB 版本:4.0
查看完整描述

1 回答

?
蓝山帝景

TA贡献1843条经验 获得超7个赞

test_doc1 使用json.RawMessagewhich 本质上是[]byte为了将其存储为表示字符串(文档的原始表示形式)的整数数组。


test_doc2 将数据存储为二进制数据,这是一种更紧凑的形式。


Go Mongo 驱动程序使用WriteBinaryWithSubtypejson 编码数据的方法,但WriteArray使用RawMessage.


不同之处在于 mongo 端用于存储这些数据的数据类型。一种是将字节切片存储为整数数组,另一种是将数据存储为具有子类型的二进制数据。与整数相比,二进制形式占用的空间更少。


深入挖掘后,我注意到 Go 驱动程序使用注册表来确定如何将值编码为 BSON。有一种专用于字节片的方法。


// ByteSliceEncodeValue is the ValueEncoderFunc for []byte.

func (dve DefaultValueEncoders) ByteSliceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {

该方法使用WriteBinary()将字节片编码为二进制数据的方法。


如果有自定义类型(即使它是底层[]byte),它将被视为切片类型并触发切片的“默认编码器”。


// SliceEncodeValue is the ValueEncoderFunc for slice types.

func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {

WriteArray()该方法依次使用该方法。


摘要:调用直接json.Marshal获取 use[]byte类型,因此它们被视为 bson 二进制类型并以紧凑二进制形式存储。json.RawMessage即使[]byte内部存储数据被视为一个切片,一个整数切片,因此作为整数数组存储在 mongo 中。


查看完整回答
反对 回复 2023-07-31
  • 1 回答
  • 0 关注
  • 186 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信