如何使用Python将MongoDB的bsondump转换为JSON?

时间:2012-08-08 15:07:38

标签: python json mongodb bson

所以我从MongoDB转储中获得了大量的.bson。我在命令行上使用bsondump,将输出作为stdin传递给python。这成功地从BSON转换为'JSON',但它实际上是一个字符串,看似不合法的JSON。

例如,传入的行看起来像这样:

{ "_id" : ObjectId( "4d9b642b832a4c4fb2000000" ),
  "acted_at" : Date( 1302014955933 ),
  "created_at" : Date( 1302014955933 ),
  "updated_at" : Date( 1302014955933 ),
  "_platform_id" : 3,
  "guid" : 72106535190265857 }

我相信的是Mongo Extended JSON

当我读到这样一行并且做:

json_line = json.dumps(line)

我明白了:

"{ \"_id\" : ObjectId( \"4d9b642b832a4c4fb2000000\" ),
\"acted_at\" : Date( 1302014955933 ),
\"created_at\" : Date( 1302014955933 ),
\"updated_at\" : Date( 1302014955933 ),
\"_platform_id\" : 3,
\"guid\" : 72106535190265857 }\n"

仍然是<type 'str'>

我也试过

json_line = json.dumps(line, default=json_util.default)

(请参阅pymongo json_util - 垃圾邮件检测阻止第三个链接) 这似乎输出与上面的转储相同。 load给出错误:

json_line = json.loads(line, object_hook=json_util.object_hook)
ValueError: No JSON object could be decoded

那么,我怎样才能将TenGen JSON的字符串转换为可解析的JSON? (最终目标是将制表符分隔数据流式传输到另一个数据库)

4 个答案:

答案 0 :(得分:13)

你所拥有的是TenGen模式中Mongo Extended JSON的转储(参见here)。一些可能的方法:

  1. 如果可以再次转储,请通过MongoDB REST API使用严格输出模式。这应该给你真正的JSON,而不是你现在拥有的。

  2. 使用http://pypi.python.org/pypi/bson/中的bson来读取您已经拥有的BSON到Python数据结构中,然后对这些BSON进行任何处理(可能输出JSON)。

  3. 使用MongoDB Python绑定连接到数据库以将数据导入Python,然后执行您需要的任何处理。 (如果需要,您可以设置本地MongoDB实例并将转储的文件导入其中。)

  4. 将Mongo Extended JSON从TenGen模式转换为Strict模式。您可以开发一个单独的过滤器来执行此操作(从stdin读取,使用Strict结构替换TenGen结构,并在stdout上输出结果),或者您可以在处理输入时执行此操作。

  5. 以下是使用Python和正则表达式的示例:

    import json, re
    from bson import json_util
    
    with open("data.tengenjson", "rb") as f:
        # read the entire input; in a real application,
        # you would want to read a chunk at a time
        bsondata = f.read()
    
        # convert the TenGen JSON to Strict JSON
        # here, I just convert the ObjectId and Date structures,
        # but it's easy to extend to cover all structures listed at
        # http://www.mongodb.org/display/DOCS/Mongo+Extended+JSON
        jsondata = re.sub(r'ObjectId\s*\(\s*\"(\S+)\"\s*\)',
                          r'{"$oid": "\1"}',
                          bsondata)
        jsondata = re.sub(r'Date\s*\(\s*(\S+)\s*\)',
                          r'{"$date": \1}',
                          jsondata)
    
        # now we can parse this as JSON, and use MongoDB's object_hook
        # function to get rich Python data structures inside a dictionary
        data = json.loads(jsondata, object_hook=json_util.object_hook)
    
        # just print the output for demonstration, along with the type
        print(data)
        print(type(data))
    
        # serialise to JSON and print
        print(json_util.dumps(data))
    

    根据您的目标,其中一个应该是一个合理的起点。

答案 1 :(得分:8)

将整个bson文档加载到python内存中是很昂贵的。

如果您想要将其流式传输而不是加载整个文件并进行全部加载,则可以尝试使用此库。

https://github.com/bauman/python-bson-streaming

from bsonstream import KeyValueBSONInput
from sys import argv
for file in argv[1:]:
    f = open(file, 'rb')
    stream = KeyValueBSONInput(fh=f,  fast_string_prematch="somthing") #remove fast string match if not needed
    for id, dict_data in stream:
        if id:
         ...process dict_data...

答案 2 :(得分:6)

您可以像这样转换bson文件的行:

>>> import bson
>>> bs = open('file.bson', 'rb').read()
>>> for valid_dict in bson.decode_all( bs ):
....

每个valid_dict元素都是一个有效的python dict,可以转换为json。

答案 3 :(得分:0)

您可以删除数据类型并使用regex获取严格的json:

import json
import re

#This will outputs a iterator that converts each file line into a dict.
def readBsonFile(filename):
    with open(filename, "r") as data_in:
        for line in data_in:
            # convert the TenGen JSON to Strict JSON
            jsondata = re.sub(r'\:\s*\S+\s*\(\s*(\S+)\s*\)',
                              r':\1',
                              line)

            # parse as JSON
            line_out = json.loads(jsondata)

            yield line_out