ฉันจะค้นหาค่าที่ทำให้เกิด bson.errors.InvalidStringData ได้อย่างไร

ฉันมีระบบที่อ่านข้อมูลจากแหล่งต่างๆ และจัดเก็บไว้ใน MongoDB ข้อมูลที่ฉันได้รับมีการเข้ารหัสอย่างถูกต้องในรูปแบบ utf-8 หรือแบบยูนิโค้ดแล้ว เอกสารมีความสัมพันธ์กันอย่างหลวมๆ และแตกต่างกันมากใน สคีมา หากคุณต้องการ

ในบางครั้ง เอกสารจะมีค่าฟิลด์ที่เป็นข้อมูลไบนารีล้วนๆ เช่น รูปภาพ JPEG ฉันรู้วิธีล้อมค่านั้นไว้ในวัตถุ bson.binary.Binary เพื่อหลีกเลี่ยงข้อยกเว้น bson.errors.InvalidStringData

มีวิธีที่จะบอกได้ว่าส่วนใดของเอกสารที่ทำให้ไดรเวอร์ pymongo เพิ่ม bson.errors.InvalidStringData หรือฉันต้องลองแปลงแต่ละฟิลด์เพื่อค้นหา

(+หากบังเอิญวัตถุไบนารี่เป็นสตริงยูนิโค้ดที่ถูกต้องหรือ utf-8 มันจะถูกจัดเก็บเป็นสตริงและก็ไม่เป็นไร)


person ixe013    schedule 15.05.2013    source แหล่งที่มา
comment
คุณช่วยสังเกตได้ไหมว่า pymongo โยน InvalidStringData ในกรณีของคุณเมื่อใด ฉันถามเพราะคุณบอกว่าข้อมูลถูกเข้ารหัสใน UTF-8 แต่ตามที่เอกสารระบุไว้ ข้อผิดพลาดนี้เกิดขึ้นขณะอ่านข้อมูลที่ไม่ใช่ UTF8 (เอกสาร) ขอบคุณ.   -  person alecxe    schedule 17.05.2013
comment
เมื่อเอกสารมีค่าฟิลด์ที่เป็นข้อมูลไบนารี่แท้ เช่น รูปภาพ JPEG หรือใบรับรอง X509 ฉันไม่เคยได้รับข้อผิดพลาดนี้ในสตริง   -  person ixe013    schedule 17.05.2013


คำตอบ (2)


PyMongo มีการใช้งาน BSON สองแบบ หนึ่งการใช้งานใน Python เพื่อการพกพา และอีกหนึ่งการใช้งานใน C เพื่อความรวดเร็ว _make_c_string ในเวอร์ชัน Python จะบอกคุณว่ามันล้มเหลวในการเข้ารหัส แต่เวอร์ชัน C ซึ่งเห็นได้ชัดว่าคุณกำลังใช้อะไรอยู่นั้นไม่ได้ทำ คุณสามารถบอกได้ว่าคุณมีการใช้งาน BSON ใดด้วย import bson; bson.has_c() ฉันได้ยื่น PYTHON-533 แล้ว เราจะแก้ไขเร็วๆ นี้

person A. Jesse Jiryu Davis    schedule 04.06.2013
comment
แน่นอน bson.has_c() ส่งคืน True ฉันจะยอมรับคำตอบของคุณแทนของฉัน - person ixe013; 04.06.2013

(ตอบคำถามของตัวเอง)

คุณไม่สามารถบอกได้จากข้อยกเว้น และจำเป็นต้องเขียนไดรเวอร์ใหม่บางส่วนเพื่อรองรับคุณสมบัตินั้น

รหัสอยู่ใน bson/__init__.py มีฟังก์ชันชื่อ _make_c_string ที่จะเพิ่ม InvalidStringData หากสตริงส่ง UnicodeError หากต้องเข้ารหัสใน utf-8 ฟังก์ชันเดียวกันนี้ ใช้สำหรับทั้งคีย์และค่า ที่เป็นสตริง

กล่าวอีกนัยหนึ่ง ณ จุดนี้ของโค้ด ไดรเวอร์จะไม่ทราบว่ากำลังจัดการกับคีย์หรือค่าอยู่หรือไม่

ข้อมูลที่ละเมิด ถูกส่ง เป็นสตริงดิบไปยังตัวสร้างข้อยกเว้น แต่ด้วยเหตุผลที่ฉันไม่เข้าใจ ข้อมูลจึงไม่ออกมาจากไดรเวอร์

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

แต่นั่นไม่สำคัญ: คุณจะต้องค้นหาคีย์สำหรับค่านั้นอยู่ดี

วิธีที่ดีที่สุดคือการวนซ้ำค่าต่างๆ โดยพยายามถอดรหัสเป็น utf-8 หากมีการยก UnicodeDecodeError ให้ล้อมค่าไว้ในวัตถุไบนารี

ค่อนข้างเช่นนี้:

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