解决Pymongo insert时会自动添加_id的问题


Posted in Python onDecember 05, 2020

在使用pymongo时遇到了一个小坑:

在Flask框架中,将字典插入mongodb后再返回就报错

@app.route('xxxx')
def main():
 ...
 data = {
 'a':'a',
 'b':'b'
 }
 mycol.insert_one(data)
 return data
Traceback (most recent call last):
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 2464, in __call__
 return self.wsgi_app(environ, start_response)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 2450, in wsgi_app
 response = self.handle_exception(e)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 1867, in handle_exception
 reraise(exc_type, exc_value, tb)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
 raise value
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 2447, in wsgi_app
 response = self.full_dispatch_request()
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 1953, in full_dispatch_request
 return self.finalize_request(rv)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 1968, in finalize_request
 response = self.make_response(rv)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/app.py", line 2112, in make_response
 rv = jsonify(rv)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/json/__init__.py", line 370, in jsonify
 dumps(data, indent=indent, separators=separators) + "\n",
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/json/__init__.py", line 211, in dumps
 rv = _json.dumps(obj, **kwargs)
 File "/home/xiang/.local/lib/python3.6/site-packages/simplejson/__init__.py", line 412, in dumps
 **kw).encode(obj)
 File "/home/xiang/.local/lib/python3.6/site-packages/simplejson/encoder.py", line 298, in encode
 chunks = list(chunks)
 File "/home/xiang/.local/lib/python3.6/site-packages/simplejson/encoder.py", line 696, in _iterencode
 for chunk in _iterencode_dict(o, _current_indent_level):
 File "/home/xiang/.local/lib/python3.6/site-packages/simplejson/encoder.py", line 652, in _iterencode_dict
 for chunk in chunks:
 File "/home/xiang/.local/lib/python3.6/site-packages/simplejson/encoder.py", line 716, in _iterencode
 o = _default(o)
 File "/home/xiang/.local/lib/python3.6/site-packages/flask/json/__init__.py", line 100, in default
 return _json.JSONEncoder.default(self, o)
 File "/home/xiang/.local/lib/python3.6/site-packages/simplejson/encoder.py", line 273, in default
 o.__class__.__name__)
TypeError: Object of type ObjectId is not JSON serializable

这是由于pymongo在进行插入操作时,如果字典中没有‘_id',会自动添加‘_id',而它的值为ObjectId实例,flask在对返回值进行编码时无法编码ObjectId类型实例,所以报错,解决办法就是去掉‘_id'或者mycol.insert_one(data.copy())

解决Pymongo insert时会自动添加_id的问题

补充知识:pymongo去重: 插入数据时,不存在则插入,存在则不执行

爬虫想把爬取的数据存入到mongoDB中, 这时候经常遇到的一个需求就是插入的数据已经存在数据库中, 因此插入前去重就是一个经常性的课题.

我的想法是:

如果数据库中已经存在这个数据, 那么就什么也不操作

如果数据不存在, 则插入这个数据

为了实现这个想法, 查了很多文献, 发现使用update 可以实现

下面就是我测试的代码

# 首先在数据中插入一条数据
document = {
  'p_id': 'f75046d73a0c4bf88f0b7342e60722c4',
  'c_name': 'Ken',
  'c_star': '5.0',
  'bought': None,
  'c_time': '2017年3月23日',
  'c_userful': 13,
  'c_comment': ['4?rになるトイプ?ドル用に?入。', '今までエサは床に食器直置きで与えていましたが、食後にむせていることがたびたび目?膜丹欷郡韦?, '「もしかして食べづらいのでは?」と思い?べてみたところ、この商品にたどり着きました。', '足が?いので食事中は?が完全に下に向いており、胃や足腰に?担がかかっていたと思われます。'],
  'gmt_create': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
}
collection.insert(document)

通过mongoDB可视化工具查看数据库,发现数据已经存在

解决Pymongo insert时会自动添加_id的问题

要实现如果不存在就插入,如果存在就不插入的要求,我们需要用到 update的一个参数:‘$setOnInsert'

$setOnInsert官方文档点击查看

通过阅读官方文档我们可以发现 与$setOnInsert方法想配合的最重要的参数就是 upsert:True

update源码中的upsert参数默认为False,只需要将update方法的upsert参数修改为True是否就能达到需要的效果呢?

现在我们执行相同数据的插入看看效果

# 首先需要限定一个重复的条件,比如我们想除了gmt_create参数以外,全部不一样就算不重复, 先限定一个条件
result_find = {
  'p_id': 'f75046d73a0c4bf88f0b7342e60722c4',
  'c_name': 'Ken',
  'c_star': '5.0',
  'bought': None,
  'c_time': '2017年3月23日',
  'c_userful': 13,
  'c_comment': ['4?rになるトイプ?ドル用に?入。', '今までエサは床に食器直置きで与えていましたが、食後にむせていることがたびたび目?膜丹欷郡韦?,
         '「もしかして食べづらいのでは?」と思い?べてみたところ、この商品にたどり着きました。', '足が?いので食事中は?が完全に下に向いており、胃や足腰に?担がかかっていたと思われます。']
}
# 执行 update
collection.update(
  result_find,
  {'$setOnInsert': document},
  upsert=True
)

执行完之后, 去数据库中查看,发现还是原来的那条数据, 并没有多出一条来, 说明可以实现 如果存在就不操作的要求

那么能实现 如果不存在就插入的要求吗?

我们去数据库可视化工具中 把数据库中的数据删除, 然后执行下面操作

document = {
  'p_id': 'f75046d73a0c4bf88f0b7342e60722c4',
  'c_name': 'Ken',
  'c_star': '5.0',
  'bought': None,
  'c_time': '2017年3月23日',
  'c_userful': 13,
  'c_comment': ['4?rになるトイプ?ドル用に?入。', '今までエサは床に食器直置きで与えていましたが、食後にむせていることがたびたび目?膜丹欷郡韦?, '「もしかして食べづらいのでは?」と思い?べてみたところ、この商品にたどり着きました。', '足が?いので食事中は?が完全に下に向いており、胃や足腰に?担がかかっていたと思われます。'],
  'gmt_create': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
}

result_find = {
  'p_id': 'f75046d73a0c4bf88f0b7342e60722c4',
  'c_name': 'Ken',
  'c_star': '5.0',
  'bought': None,
  'c_time': '2017年3月23日',
  'c_userful': 13,
  'c_comment': ['4?rになるトイプ?ドル用に?入。', '今までエサは床に食器直置きで与えていましたが、食後にむせていることがたびたび目?膜丹欷郡韦?,
         '「もしかして食べづらいのでは?」と思い?べてみたところ、この商品にたどり着きました。', '足が?いので食事中は?が完全に下に向いており、胃や足腰に?担がかかっていたと思われます。']
}

# collection.insert(document)
collection.update(
  result_find,
  {'$setOnInsert': document},
  upsert=True
)

然后我们发现数据中出现了我们想看到的这条数据

所以, 实现了我们的要求: 存在则不操作, 不存在则插入.

以上这篇解决Pymongo insert时会自动添加_id的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python与shell的3种交互方式介绍
Apr 11 Python
python从网络读取图片并直接进行处理的方法
May 22 Python
Python3 socket同步通信简单示例
Jun 07 Python
Django之无名分组和有名分组的实现
Apr 16 Python
Django框架使用内置方法实现登录功能详解
Jun 12 Python
python requests使用socks5的例子
Jul 25 Python
Python实现性能自动化测试竟然如此简单
Jul 30 Python
python调用函数、类和文件操作简单实例总结
Nov 29 Python
Python3 实现减少可调用对象的参数个数
Dec 20 Python
TensorFlow实现保存训练模型为pd文件并恢复
Feb 06 Python
Python调用接口合并Excel表代码实例
Mar 31 Python
Python selenium的这三种等待方式一定要会!
Jun 10 Python
用python对oracle进行简单性能测试
Dec 05 #Python
python mongo 向数据中的数组类型新增数据操作
Dec 05 #Python
python自动从arxiv下载paper的示例代码
Dec 05 #Python
python使用dlib进行人脸检测和关键点的示例
Dec 05 #Python
python从ftp获取文件并下载到本地
Dec 05 #Python
python基于socket模拟实现ssh远程执行命令
Dec 05 #Python
Python实现PS滤镜中的USM锐化效果
Dec 04 #Python
You might like
星际争霸 Starcraft 发展史
2020/03/14 星际争霸
PHP开发者常犯的10个MySQL错误更正剖析
2012/01/30 PHP
用php实现选择排序的解决方法
2013/05/04 PHP
php的memcache类分享(memcache队列)
2014/03/26 PHP
Yii使用DbTarget实现日志功能的示例代码
2020/07/21 PHP
地震发生中逃生十大法则
2008/05/12 Javascript
增强用户体验友好性之jquery easyui window 窗口关闭时的提示
2012/06/22 Javascript
extjs 分页使用jsp传递数据示例
2014/07/29 Javascript
node.js中的fs.truncateSync方法使用说明
2014/12/15 Javascript
javascript实现window.print()去除页眉页脚
2014/12/30 Javascript
JSONP跨域请求实例详解
2016/07/04 Javascript
JS实现改变HTML上文字颜色和内容的方法
2016/12/30 Javascript
vue-cli项目如何使用vue-resource获取本地的json数据(模拟服务端返回数据)
2017/08/04 Javascript
纯html+css+javascript实现楼层跳跃式的页面布局(实例代码)
2017/10/25 Javascript
解决npm管理员身份install时出现权限的问题
2018/03/16 Javascript
在Vue 中使用Typescript的示例代码
2018/09/10 Javascript
vue中的过滤器实例代码详解
2019/06/06 Javascript
js获取 gif 的帧数的代码实例
2019/09/10 Javascript
深入理解javascript prototype的相关知识
2019/09/19 Javascript
js验证密码强度解析
2020/03/18 Javascript
vue路由跳转传递参数的方式总结
2020/05/10 Javascript
vue绑定class的三种方法
2020/12/24 Vue.js
[01:00:53]OG vs IG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[01:04:08]完美世界DOTA2联赛PWL S3 INK ICE vs GXR 第一场 12.16
2020/12/18 DOTA
详解python的数字类型变量与其方法
2016/11/20 Python
CSS3教程(3):border-color网页边框色彩
2009/04/02 HTML / CSS
基于css3仿造window7的开始菜单
2010/06/17 HTML / CSS
使用CSS实现弹性视频html5案例实践
2012/12/26 HTML / CSS
Giuseppe Zanotti美国官方网站:将鞋履视为高级时装般精心制作
2018/02/06 全球购物
介绍一下代理模式(Proxy)
2014/10/17 面试题
硅酸盐工业控制专业应届生求职信
2013/11/02 职场文书
营销与策划应届生求职信
2013/11/04 职场文书
小学教师岗位职责
2013/11/25 职场文书
学校后勤岗位职责
2014/02/19 职场文书
会计岗位描述
2014/02/22 职场文书
医学生求职自荐书
2014/06/12 职场文书