2012-08-08 4 views
16

Quindi ho un'enorme quantità di .bson da un dump di MongoDB. Sto usando bsondump sulla riga di comando, piping l'output come stdin a python. Questo converte con successo da BSON a 'JSON' ma in realtà è una stringa, e apparentemente non legale JSON.Come posso usare Python per trasformare bsondump di MongoDB in JSON?

Per esempio una linea in ingresso si presenta così:

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

Quale I belive è Mongo Extended JSON.

Quando ho letto in una tale linea e fare:

json_line = json.dumps(line) 

ottengo:

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

che è ancora <type 'str'>.

Ho anche provato

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

(vedi pymongo json_util - rilevamento dello spam impedisce un terzo link) che sembra uscita lo stesso di discariche sopra. carichi dà un errore:

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

Quindi, come posso trasformare la stringa di TenGen JSON in JSON parseable? (l'obiettivo finale è quello di trasmettere scheda dati separati a un altro database)

+1

Hai guardato 'bson'? http://pypi.python.org/pypi/bson/0.3.2 –

+0

Non fa altro che rimuovere una dipendenza Mongo? Non capisco come possa essere il mio problema, ma lo guarderò ancora un po '. –

+0

possibile duplicato di [Impossibile deserializzare PyMongo ObjectId da JSON] (http://stackoverflow.com/questions/8409194/unable-to-deserialize-pymongo-objectid-from-json) –

risposta

10

quello che hai è una discarica in Mongo estesa JSON in modalità Tengen (vedi here). Alcuni possibili modi per andare:

    Se è possibile eseguire nuovamente il dump, utilizzare la modalità di output rigoroso tramite l'API REST di MongoDB. Questo dovrebbe darti un vero JSON invece di quello che hai ora.
  1. Utilizzare bson da http://pypi.python.org/pypi/bson/ per leggere il BSON già presente nelle strutture di dati Python e quindi eseguire qualsiasi elaborazione di cui si necessita su tali dati (possibilmente in uscita JSON).

  2. Utilizzare i binding Python MongoDB per connettersi al database per ottenere i dati in Python e quindi eseguire qualsiasi elaborazione necessaria. (Se necessario, è possibile impostare un'istanza MongoDB locale e importare i file scaricati in quello.)

  3. Convertire il JSON Mongo Extended dalla modalità TenGen alla modalità Strict. Potresti sviluppare un filtro separato per farlo (leggi da stdin, sostituisci le strutture TenGen con strutture Strict e produci il risultato su stdout) oppure puoi farlo mentre elabori l'input.

Ecco un esempio utilizzando Python e le espressioni regolari:

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)) 

A seconda del vostro obiettivo, uno di questi dovrebbe essere un punto di partenza ragionevole.

+0

Sì, ho collegato a quella pagina JSON estesa nella mia domanda. Ho provato la libreria BSON e non ha raggiunto il mio obiettivo. bsondump era l'unica cosa che potevo mettere a lavoro, ma mi dava una stringa. Il dumping o il ricaricamento dei dati non sono opzioni praticabili. –

+1

@PeterNachbaur: ho aggiunto un'opzione alla mia risposta per mostrare come è possibile convertire il formato JSON TenGen in JSON rigoroso. È più quello che avevi in ​​mente? –

+0

Grazie per continuare ad aiutare :) ora i carichi funzionano. Alla fine suppongo che intendi json.dumps non json_util.dumps (quest'ultimo non sembra esistere) ma non funziona. Tuttavia, non sono sicuro di averne bisogno ora che ho un dittico. Saluti! –

6

è possibile convertire righe del file BSON in questo modo:

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

Ogni valid_dict sarà un dict python valido che è possibile convertire in JSON.

+0

Che per ciclo non funziona :( Traceback (chiamata più recente scorso): file "", linea 1, in File "/usr/local/lib/python2.7/dist-packages/bson /__init__.py ", riga 473, in decode_all end = len (data) - 1 TypeError: oggetto di tipo 'file' non ha len() –

8

caricamento di un intero documento bson in memoria python è costoso.

Se si desidera eseguire lo streaming anziché caricare l'intero file e caricare tutto, è possibile provare questa libreria.

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...