Bagaimana saya bisa menemukan nilai mana yang menyebabkan bson.errors.InvalidStringData

Saya memiliki sistem yang membaca data dari berbagai sumber dan menyimpannya di MongoDB. Data yang saya terima sudah dikodekan dengan benar dalam utf-8 atau unicode. Dokumen memiliki keterkaitan yang longgar dan skema sangat bervariasi, jika Anda mau.

Sesekali, dokumen memiliki nilai bidang yang merupakan data biner murni, seperti gambar JPEG. Saya tahu cara membungkus nilai itu dalam objek bson.binary.Binary untuk menghindari pengecualian bson.errors.InvalidStringData.

Apakah ada cara untuk mengetahui bagian mana dari dokumen yang membuat driver pymongo memunculkan bson.errors.InvalidStringData, atau apakah saya harus mencoba dan mengonversi setiap bidang untuk menemukannya?

(+Jika kebetulan objek biner merupakan string unicode atau utf-8 yang valid, objek tersebut akan disimpan sebagai string dan tidak masalah)


person ixe013    schedule 15.05.2013    source sumber
comment
Bisakah Anda mencatat kapan pymongo menampilkan InvalidStringData dalam kasus Anda? Saya bertanya karena Anda mengatakan bahwa data dikodekan dalam UTF-8, tetapi, seperti yang disebutkan dalam dokumentasi, kesalahan ini muncul saat membaca data non-UTF8 (dokumen). Terima kasih.   -  person alecxe    schedule 17.05.2013
comment
Ini terjadi ketika dokumen memiliki nilai bidang yang merupakan data biner murni, seperti gambar JPEG atau sertifikat X509. Saya tidak pernah mendapatkan kesalahan ini pada string.   -  person ixe013    schedule 17.05.2013


Jawaban (2)


PyMongo memiliki dua implementasi BSON, satu dengan Python untuk portabilitas dan satu lagi di C untuk kecepatan. _make_c_string dalam versi Python akan memberi tahu Anda apa yang gagal dikodekan tetapi versi C, yang ternyata Anda gunakan, tidak. Anda dapat mengetahui implementasi BSON mana yang Anda miliki dengan import bson; bson.has_c(). Saya telah mengajukan PYTHON-533, masalah ini akan segera diperbaiki.

person A. Jesse Jiryu Davis    schedule 04.06.2013
comment
Memang, bson.has_c() mengembalikan True. Saya akan menerima jawaban Anda, bukan jawaban saya. - person ixe013; 04.06.2013

(Menjawab pertanyaan saya sendiri)

Anda tidak dapat membedakannya dari pengecualian, dan diperlukan penulisan ulang driver untuk mendukung fitur tersebut.

Kodenya ada di bson/__init__.py. Ada fungsi bernama _make_c_string yang memunculkan InvalidStringData jika string memunculkan UnicodeError jika ingin dikodekan dalam utf-8. Fungsi yang sama digunakan untuk kunci dan nilai yang berupa string.

Dengan kata lain, pada titik kode ini, pengemudi tidak mengetahui apakah ia berurusan dengan kunci atau nilai.

Data yang melanggar adalah diteruskan sebagai string mentah ke konstruktor pengecualian, tetapi karena alasan yang saya tidak mengerti, data tersebut tidak keluar dari driver.

>>> bad['zzz'] = '0\x82\x05\x17'
>>> try:
...     db.test.insert(bad)
... except bson.errors.InvalidStringData as isd:
...     print isd
...
strings in documents must be valid UTF-8

Namun itu tidak menjadi masalah: Anda tetap harus mencari kunci untuk nilai tersebut.

Cara terbaik adalah mengulangi nilai-nilai tersebut, mencoba memecahkan kodenya di utf-8. Jika UnicodeDecodeError dimunculkan, bungkus nilainya dalam objek Biner.

Agak seperti ini:

try:
    #This code could deal with other encodings, like latin_1
    #but that's not the point here
    value.decode('utf-8')
except UnicodeDecodeError:
    value = bson.binary.Binary(str(value))
person ixe013    schedule 28.05.2013