使用 Pymongo 插入文档 - InvalidDocument:无法编码对象
Inserting a document with Pymongo - InvalidDocument: Cannot encode object
我正在尝试使用 PyMongo 将文档(在本例中为 Twitter 信息)插入 Mongo 数据库。
如下所示,tweets_listdt[0] 与
完全相同
{
'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'
}
但是我无法将 tweets_listdt[0] 保存到我的 Mongodb 中,而我可以使用后者保存。
In[529]: tweets_listdt[0] == {'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'}
Out[528]: **True**
这个失败了:
In[530]: tweetsdb.save(tweets_listdt[0])
tweetsdb.save({'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'})
Traceback (most recent call last):
File "D:\Program Files\Anaconda\lib\site-packages\IPython\core\interactiveshell.py", line 3035, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-529-b1b81c04d5ad>", line 1, in <module>
tweetsdb.save(tweets_listdt[0])
File "D:\Program Files\Anaconda\lib\site-packages\pymongo\collection.py", line 1903, in save
check_keys, manipulate, write_concern)
File "D:\Program Files\Anaconda\lib\site-packages\pymongo\collection.py", line 430, in _insert
gen(), check_keys, self.codec_options, sock_info)
InvalidDocument: **Cannot encode object: 2704548373**
这个工作正常:
In[531]: tweetsdb.save({'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'})
Out[530]: **ObjectId('554b38d5c3d89c09688b1149')**
5 月 10 日更新
谢谢伯尼。我使用的 PyMongo 版本是 3.0.1.
这里是检查id的数据类型:
In[36]:type(tweets_listdt[0]['id'])
Out[37]:long
如果我只使用:
for tweet in tweets_listdt:
tweetsdb.save(tweet)
会出现上述错误。
但是如果我添加这一行,一切都很好:
tweet['id'] = int(tweet['id'])
而当我直接赋值时
tweets_listdtw = {'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist'}
tweetsdb.save(tweets_listdtw) 正在工作,
print type(tweets_listdtw['id'])
<type 'numpy.int64'>
又糊涂了。。。long类型肯定是可以的。。。但是为什么我把'id'改成int后,保存就可以了?
你的问题是 numpy.int64
对 MongoDB 来说是陌生的。我曾经也有过一样的问题。
解决方案是将有问题的值转换为 MongoDB 可以理解的数据类型,这是我如何在代码中转换这些有问题的值的示例:
try:
collection.insert(r)
except pymongo.errors.InvalidDocument:
# Python 2.7.10 on Windows and Pymongo are not forgiving
# If you have foreign data types you have to convert them
n = {}
for k, v in r.items():
if isinstance(k, unicode):
for i in ['utf-8', 'iso-8859-1']:
try:
k = k.encode(i)
except (UnicodeEncodeError, UnicodeDecodeError):
continue
if isinstance(v, np.int64):
self.info("k is %s , v is %s" % (k, v))
v = int(v)
self.info("V is %s" % v)
if isinstance(v, unicode):
for i in ['utf-8', 'iso-8859-1']:
try:
v = v.encode(i)
except (UnicodeEncodeError, UnicodeDecodeError):
continue
n[k] = v
collection.insert(n)
希望对您有所帮助。
我非常喜欢 Oz 的回答。用 python 3 扩展它:
def correct_encoding(dictionary):
"""Correct the encoding of python dictionaries so they can be encoded to mongodb
inputs
-------
dictionary : dictionary instance to add as document
output
-------
new : new dictionary with (hopefully) corrected encodings"""
new = {}
for key1, val1 in dictionary.items():
# Nested dictionaries
if isinstance(val1, dict):
val1 = correct_encoding(val1)
if isinstance(val1, np.bool_):
val1 = bool(val1)
if isinstance(val1, np.int64):
val1 = int(val1)
if isinstance(val1, np.float64):
val1 = float(val1)
new[key1] = val1
return new
它对那些嵌套文档有递归,我认为 python 3 将所有字符串存储为 unicode,所以我删除了编码部分。
我尝试使用愚蠢的解决方案,但它有效。假设 x
是 numpy.int32
或 numpy.int64
类型的变量。这个 int(str(x))
简单的转换工作正常PyMongo
- 如果你有 ex 的 numpy 对象。 json/dict data_dict 中的 int 或 float,您要使用 pymongo.
通过 mongo 发送
- 可能会出现 “无法编码对象” 错误,为了解决这个问题,我使用了这样的自定义编码器。
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, numpy.integer):
return int(obj)
elif isinstance(obj, numpy.floating):
return float(obj)
elif isinstance(obj, numpy.ndarray):
return obj.tolist()
else:
return super(CustomEncoder, self).default(obj)
data_dict_1 = json.dumps(data_dict,cls=CustomEncoder)
data_dict_final = json.loads(data_dict_1)
- 请在此处查看文档 https://docs.python.org/3/library/json.html
- 无论您的 Json 数据如何组织,这种方式都有效。
我正在尝试使用 PyMongo 将文档(在本例中为 Twitter 信息)插入 Mongo 数据库。
如下所示,tweets_listdt[0] 与
完全相同{
'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'
}
但是我无法将 tweets_listdt[0] 保存到我的 Mongodb 中,而我可以使用后者保存。
In[529]: tweets_listdt[0] == {'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'}
Out[528]: **True**
这个失败了:
In[530]: tweetsdb.save(tweets_listdt[0])
tweetsdb.save({'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'})
Traceback (most recent call last):
File "D:\Program Files\Anaconda\lib\site-packages\IPython\core\interactiveshell.py", line 3035, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-529-b1b81c04d5ad>", line 1, in <module>
tweetsdb.save(tweets_listdt[0])
File "D:\Program Files\Anaconda\lib\site-packages\pymongo\collection.py", line 1903, in save
check_keys, manipulate, write_concern)
File "D:\Program Files\Anaconda\lib\site-packages\pymongo\collection.py", line 430, in _insert
gen(), check_keys, self.codec_options, sock_info)
InvalidDocument: **Cannot encode object: 2704548373**
这个工作正常:
In[531]: tweetsdb.save({'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist \u2013 Machine learning, Python, Pandas, Statistics @adam_rab in London, United Kingdom http://t.co/pIIJVPCuN8\u2026'})
Out[530]: **ObjectId('554b38d5c3d89c09688b1149')**
5 月 10 日更新
谢谢伯尼。我使用的 PyMongo 版本是 3.0.1.
这里是检查id的数据类型:
In[36]:type(tweets_listdt[0]['id'])
Out[37]:long
如果我只使用:
for tweet in tweets_listdt:
tweetsdb.save(tweet)
会出现上述错误。
但是如果我添加这一行,一切都很好:
tweet['id'] = int(tweet['id'])
而当我直接赋值时
tweets_listdtw = {'created_at': u'Sun Aug 03 17:07:24 +0000 2014',
'id': 2704548373,
'name': u'NoSQL',
'text': u'RT @BigdataITJobs: Data Scientist'}
tweetsdb.save(tweets_listdtw) 正在工作,
print type(tweets_listdtw['id'])
<type 'numpy.int64'>
又糊涂了。。。long类型肯定是可以的。。。但是为什么我把'id'改成int后,保存就可以了?
你的问题是 numpy.int64
对 MongoDB 来说是陌生的。我曾经也有过一样的问题。
解决方案是将有问题的值转换为 MongoDB 可以理解的数据类型,这是我如何在代码中转换这些有问题的值的示例:
try:
collection.insert(r)
except pymongo.errors.InvalidDocument:
# Python 2.7.10 on Windows and Pymongo are not forgiving
# If you have foreign data types you have to convert them
n = {}
for k, v in r.items():
if isinstance(k, unicode):
for i in ['utf-8', 'iso-8859-1']:
try:
k = k.encode(i)
except (UnicodeEncodeError, UnicodeDecodeError):
continue
if isinstance(v, np.int64):
self.info("k is %s , v is %s" % (k, v))
v = int(v)
self.info("V is %s" % v)
if isinstance(v, unicode):
for i in ['utf-8', 'iso-8859-1']:
try:
v = v.encode(i)
except (UnicodeEncodeError, UnicodeDecodeError):
continue
n[k] = v
collection.insert(n)
希望对您有所帮助。
我非常喜欢 Oz 的回答。用 python 3 扩展它:
def correct_encoding(dictionary):
"""Correct the encoding of python dictionaries so they can be encoded to mongodb
inputs
-------
dictionary : dictionary instance to add as document
output
-------
new : new dictionary with (hopefully) corrected encodings"""
new = {}
for key1, val1 in dictionary.items():
# Nested dictionaries
if isinstance(val1, dict):
val1 = correct_encoding(val1)
if isinstance(val1, np.bool_):
val1 = bool(val1)
if isinstance(val1, np.int64):
val1 = int(val1)
if isinstance(val1, np.float64):
val1 = float(val1)
new[key1] = val1
return new
它对那些嵌套文档有递归,我认为 python 3 将所有字符串存储为 unicode,所以我删除了编码部分。
我尝试使用愚蠢的解决方案,但它有效。假设 x
是 numpy.int32
或 numpy.int64
类型的变量。这个 int(str(x))
简单的转换工作正常PyMongo
- 如果你有 ex 的 numpy 对象。 json/dict data_dict 中的 int 或 float,您要使用 pymongo. 通过 mongo 发送
- 可能会出现 “无法编码对象” 错误,为了解决这个问题,我使用了这样的自定义编码器。
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, numpy.integer):
return int(obj)
elif isinstance(obj, numpy.floating):
return float(obj)
elif isinstance(obj, numpy.ndarray):
return obj.tolist()
else:
return super(CustomEncoder, self).default(obj)
data_dict_1 = json.dumps(data_dict,cls=CustomEncoder)
data_dict_final = json.loads(data_dict_1)
- 请在此处查看文档 https://docs.python.org/3/library/json.html
- 无论您的 Json 数据如何组织,这种方式都有效。