【问题标题】:Inserting a document with Pymongo - InvalidDocument: Cannot encode object使用 Pymongo 插入文档 - InvalidDocument:无法编码对象
【发布时间】:2023-03-05 04:23:02
【问题描述】:

我正在尝试使用 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 之后,保存工作?

【问题讨论】:

  • id 的数据类型是什么?你能告诉我们你是如何为id赋值的吗?
  • 谢谢,thegreenogre。我从 twitter api 阅读了整个字典,'id': 2704548373 是字典中的项目之一。一切正常,当我直接将字典保存到数据库时生成了一个 ObjectID。因为有很多这样的字典,所以我将所有字典组合到一个名为 tweets_listdt 的列表中,这样我就可以使用 for 循环将这些字典保存到数据库中。然后就出现了这个问题。
  • 如果您没有在文档中使用原生类型(字符串、整数、日期、布尔值等),您需要确保其编码正确。尝试对 id (tweets_listdt[0]['id']=int(tweets_listdt[0]['id'])) 的值进行类型转换。
  • 太棒了!问题已经解决了。 id 的数据类型很长,不接受。非常感谢!
  • 这条评论让我很困惑。 long 绝对是 PyMongo 中支持的数据类型。错误消息来自 PyMongo 的 C 扩展。我刚刚使用您的示例文档进行了测试,无论有没有 C 扩展,它对我来说都很好。你确定'id'的数据类型很长吗?你用的是什么版本的 PyMongo?

标签: python mongodb pymongo


【解决方案1】:

您的问题是 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)

我希望这对你有帮助。

【讨论】:

    【解决方案2】:
    1. 如果你有 numpy 对象作为 ex。 int 或 float 在您想要使用 pymongo 通过 mongo 发送的 json/dict data_dict 中。
    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)
    

    【讨论】:

      【解决方案3】:

      我非常喜欢 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,所以我删除了编码部分。

      【讨论】:

      • python 设置好像有问题。添加新的 if 并将它们转换为列表:if isinstance(val, set): val = list(val)
      • def correct_encoding(self, obj): if isinstance(obj, np.bool_): return bool(obj) if isinstance(obj, np.int64): return int(obj) if isinstance(obj, np.float64): return float(obj) if type(obj) is dict: # Nested dictionaries return {key1: self.correct_encoding(val1) for key1, val1 in obj.items()} elif type(obj) is list: return [self.correct_encoding(_) for _ in obj] return obj 重构为也包含列表
      【解决方案4】:

      我尝试使用愚蠢的解决方案,但它有效.. 假设 xnumpy.int32numpy.int64 类型变量.. 这个 int(str(x)) 简单的转换在 PyMongo 上工作正常

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-28
        • 1970-01-01
        • 1970-01-01
        • 2021-10-24
        • 2019-08-15
        • 2017-11-17
        • 1970-01-01
        相关资源
        最近更新 更多