用go和mgo读取mongodump输出

时间:2014-06-13 04:13:47

标签: mongodb go mgo

我正在尝试读取mongodump生成的集合转储。该文件是几千兆字节,所以我想逐步读取它。

我可以用这样的东西读取第一个对象:

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

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

但是我不知道消耗了多少buf,所以我不知道如何阅读下一个。

这可以用mgo吗?

4 个答案:

答案 0 :(得分:4)

单独使用mgo bson.Unmarshal()是不够的 - 该函数旨在使[]byte代表单个文档,并将其解组为值。

您需要一个可以从转储文件中读取下一个整个文档的函数,然后您可以将结果传递给bson.Unmarshal()

将其与encoding/jsonencoding/gob相比较,如果mgo.bson的{​​{1}}类型使用了来自Reader的文档,则会很方便。

无论如何,从source for mongodump看,转储文件看起来只是一系列bson文档,没有文件页眉/页脚或显式记录分隔符。

BSONTool::processFile显示了mongorestore如何读取转储文件。他们的代码读取4个字节来确定文档的长度,然后使用该大小来读取文档的其余部分。确认大小前缀是bson spec的一部分。

这是一个playground example,显示如何在Go中完成:读取长度字段,阅读文档的其余部分,解组,重复。

答案 1 :(得分:3)

方法File.Read返回读取的字节数。

File.Read

  

读取从文件中读取最多len(b)个字节。它返回读取的字节数和错误(如果有)。 EOF通过零计数发出信号,错误设置为io.EOF。

因此,只需存储读取的返回参数即可获得读取的字节数:

n, err := f.Read(buf)

答案 2 :(得分:2)

我设法使用以下代码解决它:

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):]
}

答案 3 :(得分:0)

Niks Keets' answer对我不起作用。不知怎的,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:]
}

当然,你必须在缓冲区的末尾处理截断的strucs。在我的情况下,我可以将整个文件加载到内存中。