Прочитайте вывод mongodump с помощью go и mgo

Я пытаюсь прочитать дамп коллекции, созданный mongodump. Файл занимает несколько гигабайт, поэтому я хочу читать его постепенно.

Я могу прочитать первый объект примерно так:

buf := make([]byte, 100000)
f, _ := os.Open(path)
f.Read(buf)

var m bson.M
bson.Unmarshal(buf, &m)

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

Возможно ли это с mgo?


person Nick Keets    schedule 13.06.2014    source источник


Ответы (4)


Одного использования bson.Unmarshal() из mgo недостаточно — эта функция предназначена для получения []byte, представляющего один документ, и преобразования его в значение.

Вам понадобится функция, которая может прочитать следующий весь документ из файла дампа, затем вы можете передать результат в bson.Unmarshal().

Сравнивая это с encoding/json или encoding/gob, было бы удобно, если бы mgo.bson имел тип Reader, потребляющий документы из io.Reader.

Во всяком случае, из источника mongodump это похоже, что файл дампа представляет собой просто серию документов bson без верхнего/нижнего колонтитула или явных разделителей записей.

BSONTool::processFile показывает, как mongorestore читает файл дампа. Их код считывает 4 байта, чтобы определить длину документа, а затем использует этот размер для чтения остальной части документа. Подтверждено, что префикс размера является частью спецификации bson.

Вот пример игровой площадки, показывающий, как это можно сделать в Go: прочитать поле длины, прочитать остальную часть документа, unmarshal, повторить.

person lnmx    schedule 13.06.2014
comment
Да, в идеале нам нужно bson.NewDecoder(...) для этого варианта использования. - person Eve Freeman; 13.06.2014

Метод File.Read возвращает количество прочитанных байтов.

File.Read

Read читает до len(b) байт из файла. Он возвращает количество прочитанных байтов и ошибку, если таковая имеется. EOF сигнализируется нулевым счетом с ошибкой, установленной на io.EOF.

Таким образом, вы можете получить количество прочитанных байтов, просто сохранив возвращаемые параметры чтения:

n, err := f.Read(buf)
person Elwinar    schedule 13.06.2014

Мне удалось решить это с помощью следующего кода:

for len(buf) > 0 {
    var r bson.Raw
    var m userObject

    bson.Unmarshal(buf, &r)
    r.Unmarshal(&m)

    fmt.Println(m)

    buf = buf[len(r.Data):]
}
person Nick Keets    schedule 16.06.2014

ответ Никса Китса мне не помог. Каким-то образом len(r.Data) всегда занимал всю длину буфера. Итак, я вышел с этим другим кодом:

for len(buff) > 0 {
    messageSize := binary.LittleEndian.Uint32(buff)
    err = bson.Unmarshal(buff, &myObject)
    if err != nil {
        panic(err)
    }

    // Do your stuff

    buff = buff[messageSize:]
}

Конечно, вы должны обрабатывать усеченные структуры в конце буфера. В моем случае я мог загрузить весь файл в память.

person javier-sanz    schedule 06.03.2018