快速统计bson文档中对象的个数

use*_*162 4 python mongodb bson

我想计算存储在 mongodb bson 文件中的文档数量,而不必通过 mongo 恢复将文件导入到数据库中。

我在 python 中能想到的最好的方法是

bson_doc = open('./archive.bson','rb')
it = bson.decode_file_iter(bson_doc)
total = sum(1 for _ in it)
print(total)
Run Code Online (Sandbox Code Playgroud)

这在理论上是可行的,但当 bson 文档很大时,实践中会很慢。有人有一种更快的方法来计算 bson 文档中的文档数量,而无需进行完整解码吗?

我目前正在使用 python 2.7 和 pymongo。 https://api.mongodb.com/python/current/api/bson/index.html

drd*_*man 5

我手头没有文件可供尝试,但我相信有一种方法 - 如果您手动解析数据。

(无文档字符串)的来源bson.decode_file_iter如下:

_UNPACK_INT = struct.Struct("<i").unpack

def decode_file_iter(file_obj, codec_options=DEFAULT_CODEC_OPTIONS):
    while True:
        # Read size of next object.
        size_data = file_obj.read(4)
        if len(size_data) == 0:
            break  # Finished with file normaly.
        elif len(size_data) != 4:
            raise InvalidBSON("cut off in middle of objsize")
        obj_size = _UNPACK_INT(size_data)[0] - 4
        elements = size_data + file_obj.read(obj_size)
        yield _bson_to_dict(elements, codec_options)
Run Code Online (Sandbox Code Playgroud)

我认为,耗时的操作是_bson_to_dict调用 - 而您不需要它。

因此,您所需要做的就是读取该文件 - 获取带有下一个文档大小的 int32 值并跳过它。然后计算您遇到过多少文档这样做。

所以,我相信这个函数应该可以解决问题:

import struct
import os
from bson.errors import InvalidBSON

def count_file_documents(file_obj):
    """Counts how many documents provided BSON file contains"""
    cnt = 0
    while True:
        # Read size of next object.
        size_data = file_obj.read(4)
        if len(size_data) == 0:
            break  # Finished with file normaly.
        elif len(size_data) != 4:
            raise InvalidBSON("cut off in middle of objsize")
        obj_size = struct.Struct("<i").unpack(size_data)[0] - 4
        # Skip the next obj_size bytes
        file_obj.seek(obj_size, os.SEEK_CUR)
        cnt += 1
    return cnt
Run Code Online (Sandbox Code Playgroud)

(不过,我还没有测试过代码。手头没有 MongoDB。)