GitHub链接:https://github.com/lianggx6/Tools/wiki/Python-MongoDB-notebook
Python MongoDB 练习
mingoDB是什么?
- 参考资料
CSDN:https://blog.csdn.net/ltuantuan/article/details/80281079
(MongoDB可视化工具Compass的使用)。一个小例子。
- MongoDB是一种非关系型数据库,不同于MySQL等关系型数据库。MongoDB中的逻辑关系为数据库->集合(表)->文档(记录),文档为最小单位。
- MongDB Compass为MongDB的可视化工具。除了常用的可视化操作,compass在集合上支持数据分析,即schema。分析后将出现图表,对于图表中的数据,点击后可自动出现在过滤器中,比较方便。

- 其他的操作可以翻一下博客,现在还是去打Python吧。
Python MongoDB连接
import pymongo
myClient = pymongo.MongoClient('IP', port) # 参数是IP和端口
mydb = myClient.admin # 此行以及下行基本可以照抄
# 此行意思基本是先获取数据库管理员的集合
mydb.authenticate("aduser", "abc%8EheGt") # 参数为用户名和密码
# 此行就是验证我们提供的账号密码是否具有在管理员集合中具有权限
- 对于pymongo库中的初始化MongoClient方法,博客中还有如下几种,uri那个没有验证成功。

- 如下为获取数据库中所有database并验证某一数据库是否存在的方法,Python2与Python3语法不同。
dblist = myClient.database_names()
if "test" in dblist:
print "exist"
- 如下语句为选中一个数据库和集合,即client.数据库名或数据库.集合名。MongoDB中对集合和数据库的显示只有在有内容插入之后才会在可视化工具中显示。
test = myClient.test2 # 选中一个数据库,如果没有则直接创建
myCollection = test.testCollection # 选中数据库中的某个集合,如果没有则直接创建
collectionList = test.list_collection_names()
print collectionList
if 'testCollection' in collectionList: # 判断集合是否存在
print "集合已存在!"
Python MongoDB插入文档
myCollection = test.testCollection # 选中集合
student = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
}
result = myCollection.insert_one(student) # 插入数据、返回InsertOneResult对象
print result
- 使用insert_many()方法可同时插入多条数据,并返回结果所在首地址.
myCollection = test.testCollection # 选中集合
mylist = [
{ "name": "Taobao", "alexa": "100", "url": "https://www.taobao.com" },
{ "name": "QQ", "alexa": "101", "url": "https://www.qq.com" },
{ "name": "Facebook", "alexa": "10", "url": "https://www.facebook.com" },
{ "name": "知乎", "alexa": "103", "url": "https://www.zhihu.com" },
{ "name": "Github", "alexa": "109", "url": "https://www.github.com" }
]
result = myCollection.insert_many(mylist) # 返回自定义对象
print result.inserted_ids # inserted_ids为id列表
- 插入文档时id可以指定,如不指定MongoDB可自动指定,且以16进制存储。如下为插入id代码。
myCollection = test.testCollection # 选中集合
mylist = [
{ "_id": 1, "name": "RUNOOB", "cn_name": "菜鸟教程"},
{ "_id": 2, "name": "Google", "address": "Google 搜索"},
{ "_id": 3, "name": "Facebook", "address": "脸书"},
{ "_id": 4, "name": "Taobao", "address": "淘宝"},
{ "_id": 5, "name": "Zhihu", "address": "知乎"}
]
result = myCollection.insert_many(mylist) # 返回自定义对象
print result.inserted_ids # inserted_ids为id列表
Python MongoDB查询数据
test = myClient.test # 选中一个数据库,如果没有则直接创建
myCollection = test.SP # 选中集合
result = myCollection.find_one({'code': "LCA3M"}) # 筛选code字段为"LCA3M"的文档
print (result)
- 使用find()方法可查询多条数据,不设过滤参数的情况下查询集合中所有文档。相当于SQL中的select *。返回类型为Cursor相当于一个生成器,其有一个已被丢弃的方法count()可查看查询的记录条数。
myCollection = test.SP # 选中集合
result = myCollection.find() # 查询所有数据
print (result)
for r in result: # 遍历输出
print r
result = myCollection.find({"code": "LCA3M", "TurnoverVol": 9716})
# 参数字典中有多个字段,相当于“与”,即查询code为LCA3M且TurnoverVol为9716的数据
result = myCollection.find({}, {"code": 0, "TurnoverVol": 0})
# 该方法第一个参数为{},即无过滤。但第二个参数为字典,其中每个字段对应0或1,代表是否查询文档的该字段。
# 注意除id外,字段的值要不都为1要不都为0.
result = myCollection.find({"$or": [{"code": "LCA3M"}, {"code": "LAH3M"}]})
# 过滤参数中"$or",其后为一列表,列表中为字典,是筛选条件且为“或关系”。即,查询code为LCA3M或者为LAH3M的记录。
result = myCollection.find({"$where": "this.fields1 == this.fields2"})
#相当于调用SQL中的where语句
result = myCollection.find({}, {"code": 1}).distinct("code")
#使用distinct去重查询
- find的过滤参数字段的条件键值还可以是字典,主要用法如下。
result = myCollection.find({"Low": {"$gt": 10000}})
# 该语句查询字段Low键值大于10000的文档。"$gt"为比较符号,代表大于。
符号 |
含义 |
示例 |
$lt |
小于 |
{"Low": {"$lt": 10000}} |
$lte |
大于 |
{"Low": {"$gt": 10000}} |
$lte |
小于等于 |
{'Low': {'$lte': 10000}} |
$gte |
大于等于 |
{'Low': {'$gte': 10000}} |
$ne |
不等于 |
{'Low': {'$ne': 10000}} |
$in |
在范围内 |
{'Low': {'$in': 10000}} |
$nin |
不在范围内 |
{'Low': {'$nin': 10000}} |
- 一些其他的用法,有四列,所以重新写个表格,反正都是copy的
符号 |
含义 |
示例 |
示例含义 |
$regex |
匹配正则表达式 |
{'name': {'$regex': '^M.*'}} |
name以M开头 |
$exists |
属性是否存在 |
{'name': {'$exists': True}} |
name属性存在 |
$type |
类型判断 |
{'age': {'$type': 'int'}} |
age的类型为int |
$mod |
数字模操作 |
{'age': {'$mod': [5, 0]}} |
年龄模5余0 |
$text |
文本查询 |
{'$text': {'$search': 'Mike'}} |
text类型的属性中包含Mike字符串 |
$where |
高级条件查询 |
{'$where': 'obj.fans_count == obj.follows_count'} |
自身粉丝数等于关注数 |
- 使用count()方法可统计数据条数,使用limit()方法限制查询数量,使用sort()方法对查询结果进行排序,使用skip()偏移几个位置。
result = myCollection.find({"Low": {"$gt": 10000}}).count()
# 查询字段Low大于10000的数据条数
result = myCollection.find({"Low": {"$gt": 10000}}).limit(3)
# 对于查询结果只取前3条。
result = myCollection.find({"Low": {"$gt": 10000}}).sort('Low', pymongo.DESCENDING)
#对于查询结果进行排序。参数为字段名和排序方式
result = myCollection.find({"Low": {"$gt": 10000}}).skip(2)
# 偏移2, 即忽略前2条文档
Python MongoDB更新数据
myCollection = test.SP # 选中集合
result = myCollection.update_one({"code":"LCA3M"},{"$set": {"Low": 1234 }})
# 将code为"LCA3M"的第一条文档的“Low”键值修改为1234
print (result.matched_count, result.modified_count)
- 对于第二个参数,除了键值为"$set"代表修改之外,还有其他的用法。例如使用"$unset"删除某一个值为多少的字段,使用"$inc"代表在原值的基础上加一个值。还有其他方法的话需要搜索查询。
result = myCollection.update_one({"code":"LCA3M"},{ "$inc": { "Low": 1234 } })
# 使用"$inc" 代表将Low字段增加1234
- 另外,对于第一个参数使用的过滤器,理论上应和find时具有一样多的筛选条件,这里不过多列举,具体使用具体搜索。
result = myCollection.update_one({"Low":{"$lt":1000}}, {"$inc": {"Low": 1000 }})
# 筛选出"Low"小于1000的文档第一条并对其修改
- update_many()使用方法基本一致,仅修改的文档数不同。
- 还有一些对单个字段进行修改的方法,描述如下:
符号 |
含义 |
$inc |
根据要添加的值递增该字段的值。 |
$mul |
将该字段的值乘以指定的值 |
$rename |
重命名字段 |
$setOnInsert |
操作时,操作给相应的字段赋值 |
$set |
用来指定一个键的值,如果不存在则创建它 |
$unset |
用来删除一个键的值 |
$min |
只有当指定的值小于现有字段值时才更新该字段 |
$max |
只有当指定的值大于现有字段值时才更新该字段 |
$currentDate |
设置当前日期字段的值,或者作为一个日期或时间戳 |
result = myCollection.update_many({"Low":{"$lt":1000}}, {"$inc": { "Low": 1000 } })
# 将所有"Low"小于1000的文档修改
Python MongoDB删除
myCollection = test.testCollection # 选中集合
result = myCollection.delete_one({"address": "知乎"})
# 将字段address为知乎的第一条文档删除
- 使用delete_many() 方法来删除多个文档,其参数为过滤器,类型为字典,指定删除哪些文档。若该字典为空,则删除所有文档。
result = myCollection.delete_many({"address": "知乎"})
# 将字段address为知乎的所有文档删除
result = myCollection.delete_many({})
# 若参数字典为空,则将该集合下所有文档删除
- 使用drop()方法可以删除掉该集合。使用上文提到的"$unset"删除某一个值为多少的字段。
myCollection.drop() # 删除myCollection集合
myCollection.update_one({"name": "Taobao"}, {"$unset": {"name": ""}})
# 将name为Taobao的文档的name字段删除
总结
- 本文总结了一些pymongo库的基本用法,但总体框架是以菜鸟教程上MongoDB的教程为主,并以其他博客为辅学习编写的。pymongo的一些方法和参数设置等,本文并没有详尽描述,还是要具体使用,具体搜索,本文只做入门和基础。
其他的小问题
- MongoDB的时间Date数据问题
- 使用pymongo对MongoDB操作时,对于其数据类型Date需格外注意。MongoDB中的Date类型与Python中的Datetime对应,但是使用pymongo向MongoDB写入Datetime时,若不指定时区,MongoDB会默认存储的时间为UTC时间,如此将会造成时间数据存储错误。解决的方法是对于datetime对象使用astimezone(pytz.timezone())方法显示的指定一个时区,再存储到MongoDB中。无论指定哪个时区,MongoDB会将其转化为对应的UTC时间并存储。这样就解决了存储到MongoDB中的时间出现错误的问题。
- 但是很不幸,我们从MongoDB读数据的时候,还会出现错误。MongoDB存储的是UTC时间,但是Python将其读出之后又当成了本地时间,这样一来又出现了时间错误。解决的办法是使用timedelta()方法将其转化为当前时区时间。
- 其实,如果你完全不考虑时区问题。你会发现,我们从Python存了一个本地时间到MongoDB,又从MongoDB拉了一个本地时间回来,除了MongoDB那里把这个时间当成了UTC时间,我们用Python的时候好像完全没影响。的确是这样,但是考虑到MongoDB的可视化编辑,还是选择在代码上麻烦一些。
- MongoDB的Cursor超时问题
- 我们使用find()方法查询MongoDB的数据时,会返回一个Cursor对象供我们访问数据。但是服务器对这个Cursor的维护默认是有限时的,限时为10分钟。如果10分钟内还没有处理完查询到的数据,服务器就会关闭这个Cursor,导致Python报出“CursorNotFound”错误。解决这种情况有以下两种方法。
- 第一种是将find()方法中的no_cursor_timeout参数置为True,意思就是该Cursor不能被超时关闭。但是这种方法必须对应的显式使用Curosr.close()方法将这个Cursor关闭,服务器将一直维护这个Cursor链接。
- 另一种方法是使用batch_size()方法。即查询时采用find().batch_size(n)这种方法,其中n应当设置为一个程序能在10分钟之内处理完的数量。