Как я могу использовать Python для преобразования bsondump MongoDB в JSON?

Итак, у меня есть огромное количество .bson из дампа MongoDB. Я использую bsondump в командной строке, передавая вывод как стандартный ввод в 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 - обнаружение спама предотвращает третью ссылку). Похоже, что выводится то же самое, что и дампы выше. загружает выдает ошибку:

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

Итак, как я могу преобразовать строку TenGen JSON в анализируемый JSON? (конечная цель состоит в том, чтобы передавать данные, разделенные табуляцией, в другую базу данных)


person Peter Nachbaur    schedule 08.08.2012    source источник
comment
Вы смотрели на bson? pypi.python.org/pypi/bson/0.3.2   -  person Nikolay Fominyh    schedule 08.08.2012
comment
Делает ли это что-нибудь, кроме удаления зависимости от Mongo? Я не понимаю, как это может быть моей проблемой, но я посмотрю на это еще немного.   -  person Peter Nachbaur    schedule 08.08.2012
comment
возможный дубликат Невозможно десериализовать PyMongo ObjectId из JSON   -  person e-satis    schedule 08.08.2012
comment
Я увидел это и попытался воспользоваться помощью. Но если вы заметили, строка, которую он получает, имеет предшествующую букву «u» перед «_id», и ответчик указал, что это представляет собой строку юникода python.   -  person Peter Nachbaur    schedule 09.08.2012
comment
@boardrider WTH это? Ссылка относится к этому вопросу.   -  person Vahid Amiri    schedule 28.03.2017
comment
Извините за путаницу, @VSG24. Я удалю это.   -  person boardrider    schedule 29.03.2017


Ответы (4)


У вас есть дамп в Mongo Extended JSON в режиме TenGen (см. здесь). Некоторые возможные пути:

  1. Если вы можете снова создать дамп, используйте строгий режим вывода через REST API MongoDB. Это должно дать вам настоящий JSON вместо того, что у вас есть сейчас.

  2. Используйте bson с http://pypi.python.org/pypi/bson/, чтобы прочитать BSON, который у вас уже есть, в Структуры данных Python, а затем выполняйте любую необходимую обработку (возможно, вывод JSON).

  3. Используйте привязки MongoDB Python для подключения к базе данных, чтобы получить данные в Python, а затем выполнить необходимую обработку. (При необходимости вы можете настроить локальный экземпляр MongoDB и импортировать в него файлы дампа.)

  4. Преобразуйте Mongo Extended JSON из режима TenGen в строгий режим. Вы можете разработать для этого отдельный фильтр (считывать со стандартного ввода, заменять структуры TenGen структурами Strict и выводить результат на стандартный вывод) или делать это во время обработки ввода.

Вот пример использования 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))

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

person Fabian Fagerholm    schedule 09.08.2012
comment
Да, я связался с этой расширенной страницей JSON в своем вопросе. Я попробовал библиотеку BSON, и она не достигла моей цели. bsondump был единственным, что я мог заставить работать, но это дает мне строку. Сброс или перезагрузка данных не являются жизнеспособными вариантами. - person Peter Nachbaur; 09.08.2012
comment
@PeterNachbaur: я добавил в свой ответ опцию, чтобы показать, как можно преобразовать формат TenGen JSON в строгий JSON. Это больше, что вы имели в виду? - person Fabian Fagerholm; 10.08.2012
comment
Спасибо, что продолжаете помогать :) теперь грузы работают. В конце я предполагаю, что вы имеете в виду json.dumps, а не json_util.dumps (последний, похоже, не существует), но это не работает. Однако я не уверен, что мне это нужно сейчас, когда у меня есть дикт. Ваше здоровье! - person Peter Nachbaur; 10.08.2012
comment
@PeterNachbaur: Нет проблем, было весело подумать об этом! :) Странно, у меня есть функция bson.json_util.dumps. Но, возможно, он существует только в ветке разработки кода mongo-python. В любом случае, у вас есть диктофон, так что теперь можете делать все, что хотите ;) Удачи! - person Fabian Fagerholm; 10.08.2012
comment
Хороший подход. регулярное выражение :) - person igorkf; 07.11.2019

загрузка всего документа 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...
person bauman.space    schedule 20.12.2013

Вы можете преобразовать строки файла bson следующим образом:

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

Каждый элемент valid_dict будет действительным python dict, который вы можете преобразовать в json.

person Emily S    schedule 09.08.2012
comment
Этот цикл for не работает :( Трассировка (последний последний вызов): Файл ‹stdin›, строка 1, в ‹module› Файл /usr/local/lib/python2.7/dist-packages/bson/__init__.py , строка 473, в decode_all end = len(data) - 1 TypeError: объект типа "файл" не имеет len() - person Peter Nachbaur; 09.08.2012

Вы можете удалить типы данных и получить строгий 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
person Maviles    schedule 04.07.2019