PyMongo造轮子
因新接手项目主使用Mongo,所以这次造轮子的主要目的是为了在接手项目中方便使用,次要目标是熟悉Pymongo
-
Mongo
- Mongo的配置文件 初始化方法
- mongo的配置
- 代码段
- 参数以及场景解析 delete_item方法
- 代码段
- 参数解析
- 测试代码及结果 insert_item方法
- 代码段
- 参数解析
- 测试代码及结果 find_item方法
- 代码段
- 参数解析
- 测试代码及结果 update_item方法
- 代码段
- 参数解析
- 测试代码及结果
下面 代码
解析。
mongo配置:
from pymongo import MongoClient
from public_tools import public_settings
mongo_info = {
'host': public_settings.MONGO_HOST
'port': public_settings.MONGO_PORT,
'username': public_settings.MONGO_USERNAME,
'password': public_settings.MONGO_PASSWORD,
}
public_tools 为自定义的公共配置方法
参照: 我使用的是局域网ip(具体配置更换自己的😊)
MONGO_HOST = '191.168.1.1'
MONGO_PORT = 27017
MONGO_USERNAME = 'username'
MONGO_PASSWORD = 'password'
初始化方法:
def __init__(self, db, table, many=True, client_close=False):
'''
初始化方法做了自动连接,创建游标
默认操作完成后,自动关闭连接
如需要手动关闭的情况,修改client_close,会返还连接对象
:param db: 哪个库
:param table: 哪张表
:param many: 操作单条还是多条数据 默认为全部
:param client_close: 是否自动关闭连接 默认为自动关闭
'''
self.uri = 'mongodb://{}:{}@{}:{}'.format(
mongo_info['username'], mongo_info['password'],
mongo_info['host'], mongo_info['port'])
self.client = MongoClient(self.uri)
db = self.client[db]
self.cursor = db[table]
self.many = many
self.client_close = client_close
因业务需求,所以我在初始化方法中直接链接mongo,创建了游标,何时释放连接由
client_close参数控制。当时加这个参的原因是出于遍历操作的场景
如:
for filter in filter_list:
client,results = cursor.find(filter)
client.close()
该情况下就需要返回链接,在循环外关闭了。
正常场景,使用默认的client_close,各操作方法内会自动关闭连接
many参数是为了控制是处理第一条符合filter条件的数据还是多条的,后续会讲
delete_item方法:
def delete_item(self, filter):
"""
删
:param filter: 筛选条件
:return:
"""
if type(filter) == dict:
if self.many:
result_data = self.cursor.delete_many(filter=filter)
result = 'delete success, delete_count: {}'.format(result_data.deleted_count)
else:
result_data = self.cursor.delete_one(filter=filter)
result = 'delete success, delete_count: {}'.format(result_data.deleted_count)
else:
result = 'filter type error...only dict'
if self.client_close == 'off':
self.client.close()
print('auto close client')
return result
else:
return self.client, result
为什么不按照增删改查的顺序来呢?是因为删的逻辑最简单 😄
delete方法外层先判断filter参数是否合规,必须为dict 例如{'age': '18'}
if type(filter) == dict:
pass
else:
result = 'filter type error'
many参数判断是操作符合条件的第一条还是全部数据,默认为全部
因为业务逻辑大部分处理的是符合条件的全部数据,所以就省事定义了默认值,写到了初始化方法中。见谅~
if self.many:
result_data = self.cursor.delete_many(filter=filter)
result = 'delete success, delete_count: {}'.format(result_data.deleted_count)
else:
result_data = self.cursor.delete_one(filter=filter)
result = 'delete success, delete_count:{}'.format(result_data.deleted_count)
然后通过delete_many方法或delete_one方法去执行操作
返回的result_data为一个对象,具体的参数可以调试查看哦
我使用了其中比较重要的deleted_count参数,返回删除成功的数据条数
client_close参数判断是需要方法内关闭,还是返回连接方法外关闭。
默认为方法内关闭连接。也是为了省事,再次见谅~
if self.client_close == False:
self.client.close()
print('auto close client')
return result
else:
return self.client, result
delete测试代码
# --------- delete_item test code ---------
MongoTool()为类方法的名字
# 第一种 删除符合filter规则的所有数据/自动关闭连接
结果: 成功删除/自动关闭连接
cursor = MongoTool(db=db, table=table)
results = cursor.delete_item(filter={'age': '18'})
# 第二种 删除符合filter规则的第一条数据/自动关闭连接
结果: 成功删除/自动关闭连接
cursor = MongoTool(db=db, table=table, many=False)
results = cursor.delete_item(filter={'age': '18'})
# 第三种 for循环删除符合filter规则的所有数据/手动关闭连接
结果: 成功删除/手动关闭连接
cursor = MongoTool(db=db, table=table, client_close=True)
filter_list = [{'age': '18'}, {'sex': 'boy'}]
for filter in filter_list:
client, results = cursor.delete_item(filter=dict(filter))
print(results)
client.close()
insert_item方法:
def insert_item(self, data):
"""
增 根据data类型判断时单条插入还是多条插入
插入数据操作
:param sql:
:return:
"""
if type(data) == dict:
try:
result_data = self.cursor.insert_one(data)
result = 'success..insert_id: {}'.format(result_data.inserted_id)
except Exception as e:
result = 'insert data error! \nErrorReason: [ {} ]'.format(e)
elif type(data) == list:
try:
result_data = self.cursor.insert_many(data)
result = 'success..insert_id_list: {}'.format(result_data.inserted_ids)
except Exception as e:
result = 'insert data error! \nErrorReason: [ {} ]'.format(e)
else:
result = 'insert_data type error'
if self.client_close == False:
self.client.close()
print('auto close client')
return result
else:
return self.client, result
insert方法判断了插入的data类型
如:
data = {'age': 13}
data1 = [{'age': 13}, {'age': 14}]
当data为dict时,判断为插入单条数据,执行insert_one()方法
当data为list时,判断为插入多条数据,执行insert_many()方法
插入成功的result主要打印了插入的inserted_id/inserted_ids
依然是根据初始化方法的client_close参数来判断是否需要在方法外关闭连接
insert测试代码
data = {'age': 13}
data1 = [{'age': 13}, {'age': 14}]
# 根据data类型判断 dict的为插入单条,list为插入多条
# 第一种 插入符合规则的一条数据/自动关闭连接
结果 # _id = 6079475810747234d503b02e 插入成功/自动关闭连接
cursor = MongoTool(db=db, table=table)
result = cursor.insert_item(data=data)
# 第二种 插入符合规则的多条数据/自动关闭连接
结果 # _ids = [ObjectId('607947dafa468affe394b555'), ObjectId('607947dafa468affe394b556')] 插入成功/自动关闭连接
cursor = MongoTool(db=db, table=table)
result = cursor.insert_item(data=data1)
# 第三种 循环插入数据/做手动关闭连接
结果
# 1-success..insert_id: 60794872d430bc78ada7e1b6 数据插入成功,
# 2-success..insert_id: 60794872d430bc78ada7e1b7 数据插入成功,
连接手动关闭成功
cursor = MongoTool(db=db, table=table, client_close='on')
for data in data1:
client, result = cursor.insert_item(data=data)
print(result)
client.close()
find_item方法:
def find_item(self, filter, limit_num=None, skip_num=None):
'''
对返回值做统一处理 空值为: [], 单条的为: [dict], 多条的没[dict1, dict2]
:param filter: 查询条件 {'字段': '值'} 默认不做分页
:param limit_num: 分页 没有skip的话,取0-limit_num条数据
:param skip_num: 起始页 有skip的话,取skip_num至skip_num+limit_num的数据 是一个区间
:return: result 为查询结果的列表,为空时代表没有符合条件的数据集
'''
if type(filter) == dict:
if self.many:
if limit_num:
if skip_num:
print('[get {}- {} data]'.format(skip_num, skip_num + limit_num))
result = list(self.cursor.find(filter).skip(skip_num).limit(limit_num))
else:
print('[get Top {} data]'.format(limit_num))
result = list(self.cursor.find(filter).limit(limit_num))
else:
print("not limit")
result = list(self.cursor.find(filter))
else:
result_dict = self.cursor.find_one(filter)
result = []
result.append(result_dict)
else:
result = 'fitter type error'
if self.client_close == 'off':
print('auto close client start')
self.client.close()
print('auto close client end')
return result
else:
return self.client, result
find_item多了俩个参数
分页 limit_num=None 有limt_num,没有skip的话,取0-limit_num条数据
起始页 skip_num=None 有skip的话,取skip_num至skip_num+limit_num的数据
方法第一层
if type(filter) == dict:
判断筛选条件是否为dict 不为dict的话,result=‘error info’
方法第二层
if self.many:
判断依然是判断操作单条还是多条数据,默认是符合filter条件的全部数据
many=True 执行find()方法
limit_num skip_num这俩个参数没有传值时,
result = list(self.cursor.find(filter)) #取出符合条件的所有数据
limit_num有传值, skip_num没有的话,
result = list(self.cursor.find(filter).limit(limit_num))
limit_num和skip_num都有传值的话,
result = list(self.cursor.find(filter).skip(skip_num).limit(limit_num))
many=False 执行find_one()方法 因为find_one返回值为dict 为了统一返回值,将dict添加至列表,返回列表
依然是根据初始化方法的client_close参数来判断是否需要在方法外关闭连接
if self.client_close == 'off':
print('auto close client start')
self.client.close()
print('auto close client end')
return result
else:
return self.client, result
# ---------- find_item test code ----------
# 第一种 查询符合规则的所有数据/未做分页/自动关闭连接 共98条数据 auto close client 查询成功/自动关闭连接
cursor = MongoTool(db=db, table=table)
results = cursor.find_item(filter={'regionName': '北京'})
# 第二种 查询符合规则的所有数据/做分页/自动关闭连接 limit_num=30 前30条数据 查询成功/自动关闭连接
cursor = MongoTool(db=db, table=table)
results = cursor.find_item(filter={'regionName': '北京'}, limit_num=30)
# 第三种 查询符合规则的所有数据/做分页/固定值开始/自动关闭连接 limit_num=30, skip_num=20 第(20条)至第(20+30条)数据 查询成功/自动关闭连接
cursor = MongoTool(db=db, table=table)
results = cursor.find_item(filter={'regionName': '北京'}, limit_num=30, skip_num=20)
# 第四种 查询符合规则的第一条数据/自动关闭连接 查询成功/自动关闭连接
cursor = MongoTool(db=db, table=table, many=False)
results = cursor.find_item(filter={'regionName': '北京'})
# 第五种 for循环取符合规则的所有获取数据/手动关闭连接/未做分页 查询成功/手动关闭连接成功
cursor = MongoTool(db=db, table=table, client_close='on')
filter_list = [{'regionName': '北京'}, {'regionName': '江苏'}]
for filter in filter_list:
client, results = cursor.find_item(filter=filter)
client.close()
print('client close')
update_item方法:
def update_item(self, filter, data, upsert=True, multi=False):
"""
:param fifter: 筛选条件
:param data: 更新数据
:param upsert: True: 存在更新 不存在插入 False: 不做插入,跳过
:param multi: True: 符合筛选条件,全部做更新 False: 只更新找到的第一条记录
:return:
"""
if type(filter) and type(data) == dict:
result_data = self.cursor.update(filter, {'$set': data}, upsert=upsert, multi=multi)
if result_data['ok'] == 1.0:
result = 'update success... filter_num: {}, modified: {}'.format(result_data['n'],
result_data['nModified'])
else:
result = 'filter or data type error...only dict'
if self.client_close == 'off':
self.client.close()
print('auto close client')
return result
else:
return self.client, result
更新涉及到问题
upsert参数
True 根据筛选条件,如果存在更新,不存在的话创建。
(省去了先查数据库,确定是否有对应文档,再决定更新还是插入。mongo🐂🍺)
multi参数
True: 符合筛选条件,全部做更新
False: 只更新找到的第一条记录
查询成功后,返回的result为符合条件的条数和已更新的条数
经测试一般使用没啥问题,但还是感觉有点别扭,具体的别扭可能是用习惯了PyMongo,我有感觉这次造轮子最后的结果可能是脱裤子放屁–>多次一举 了😭, 不过只好安慰自己,当学习过程了,学习下mongo的使用和封装要考虑的多重可能性 喏 奖励自己个赞~👍