我有一个从各种来源读取数据并将它们存储在MongoDB中的系统。我收到的数据已经在utf-8或unicode中正确编码。如果您愿意,文档与架构有很大关系并且差异很大。
文档的字段值是纯二进制数据,就像JPEG图像一样。我知道如何在bson.binary.Binary
对象中包装该值以避免bson.errors.InvalidStringData
异常。
有没有办法告诉文件的哪一部分让pymongo司机提出bson.errors.InvalidStringData
,或者我是否必须尝试转换每个字段才能找到它?
(+如果偶然的二进制对象碰巧是有效的unicode字符串或utf-8,它将被存储为字符串,这没关系)
答案 0 :(得分:3)
PyMongo有两个BSON实现,一个用Python实现可移植性,一个用C实现速度。 Python版本中的_make_c_string
将告诉您它编码失败的原因,但C版本(显然是您正在使用的版本)却没有。您可以使用import bson; bson.has_c()
确定您拥有的BSON实施方式。我已经提交了PYTHON-533,很快就会修复。
答案 1 :(得分:0)
(回答我自己的问题)
您无法从异常中分辨出来,并且需要对驱动程序进行一些重写才能支持该功能。
代码位于bson/__init__.py
。如果要在utf-8中编码,则如果string抛出UnicodeError,则会有一个名为_make_c_string
的函数引发InvalidStringData
。相同的功能用于键和值,它们都是字符串。
换句话说,在代码的这一点上,驱动程序不知道它是在处理密钥还是值。
违规数据 作为原始字符串传递给异常的构造函数,但由于某种原因我不明白,它并不是来自驱动程序。
>>> 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
,请将值包装在Binary对象中。
有点像这样:
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))