使用 Pymongo 插入文档 - 无效文档:无法编码对象

问题描述 投票:0回答:5

我正在尝试使用 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'>

又困惑了...所以绝对长类型是可以的...但是为什么在我将 'id' 更改为 int 后,保存起作用了?

python mongodb pymongo
5个回答
18
投票

你的问题是

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)

我希望这对您有帮助。


10
投票
  1. 如果你有 numpy 对象。您想要使用 pymongo 通过 mongo 发送的 json/dict data_dict 中的 int 或 float 。
  2. 有人可能会得到“无法编码对象”错误,为了解决这个问题,我使用了这样的自定义编码器。

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)

5
投票

我非常喜欢奥兹的回答。使用 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,所以我删除了编码部分。


2
投票

我尝试使用愚蠢的解决方案,但它有效..假设

x
numpy.int32
numpy.int64
类型变量..这个
int(str(x))
简单的转换与PyMongo一起工作得很好


0
投票

如果您尝试在 mongodb 中插入类对象,则需要将其转换为字典表示形式。您无法插入直接对象。

{"key": class_object__dict__}
© www.soinside.com 2019 - 2024. All rights reserved.