Почему json.RawMessage увеличивает размер документа mongoDb? - PullRequest
0 голосов
/ 12 октября 2019

Следующие коды пытаются вставить новые документы в 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())
111

Object.bsonsize(db.test_doc1.findOne())
556

Размер test_doc1 больше test_doc2,Почему?

Per bson doc

Array - документ для массива - это обычный документ BSON с целочисленными значениями для ключей, начиная с 0 и продолжаяпоследовательно. Например, массив ['red', 'blue'] будет закодирован как документ {'0': 'red', '1': 'blue'}. Ключи должны быть в порядке возрастания.

Может ли массив Bson занимать больше места на диске? Я прав?

Версия MongoDB: 4.0

1 Ответ

6 голосов
/ 12 октября 2019

test_doc1 использует json.RawMessage, что по сути []byte, поэтому он сохраняется как массив целых чисел, представляющих строку (необработанное представление документа).

test_doc2 хранит данные в виде двоичных данных, которые представляют собой более компактную форму.

Драйвер Go Mongo использует метод WriteBinaryWithSubtype для данных, закодированных в json, но использует WriteArray для RawMessage.

Разница заключается в типе данных, которые используются на стороне монго для хранения этих данных. Один хранит срез байтов как массив целых чисел, другой хранит данные как двоичные с подтипом. Двоичная форма занимает меньше места по сравнению с целыми числами.

Копая глубже, я заметил, что драйвер 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 напрямую использует типы []byte, поэтому они обрабатываются как двоичный тип bson и сохраняются в компактной двоичной форме. json.RawMessage, хотя данные хранятся как []byte, внутренне обрабатываются как срез, срез целых чисел и, таким образом, сохраняются в монго как массив целых чисел.

...