我正在尝试使用 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')**
谢谢伯尼。我使用的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'>
又困惑了...所以绝对长类型是可以的...但是为什么在我将 '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)
我希望这对您有帮助。
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)
我非常喜欢奥兹的回答。使用 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一起工作得很好
如果您尝试在 mongodb 中插入类对象,则需要将其转换为字典表示形式。您无法插入直接对象。
{"key": class_object__dict__}