最全总结 | 聊聊 Python 数据处理全家桶(MongoDB 篇)

image

1. 前言

前面 4 篇文章,分别对 Python 处理 Mysql、Sqlite、Redis、Memcache 数据进行了总结,本篇文章继续聊另外一种数据类型:MongoDB

最全总结 | 聊聊 Python 数据处理全家桶(Mysql 篇)

​最全总结 | 聊聊 Python 数据处理全家桶(Sqlite 篇)

最全总结 | 聊聊 Python 数据处理全家桶(Redis 篇)

最全总结 | 聊聊 Python 数据处理全家桶(Memcached 篇)

MongoDB 是基于分布式存储,由 C++ 编写的开源的 NoSql 数据库

MongoDB 的内容存储类似 JSON 对象,数据结构包含 3 种

分别是:

  • 数据库 - Databases

    对应关系型数据库中的数据库(Database)

  • 集合 - Collection

    对应关系型数据库中的 Table 表(Table)

  • 文档 - Document

    对应数据库表中的一条数据(Row Data)

2. 准备

Python 操作 MongoDB,常见的两种方式是:Pymongo、Mongoengine

其中

  • Mongoengine:面相对象,针对文档型数据库的 ORM,直接继承于 Document 文档,对文档进行增删改查

  • Pymongo:通过 JSON 和 MongoDB 进行通信,将 MongoDB 的数据映射成 Python 内置的数据类型

首先,我们通过 pip3 命令安装依赖

# 安装依赖
# pymongo
pip3 install pymongo

# mongoengine
pip3 install mongoengine

下面分别对 Pymongo 和 Mongoengine 进行说明

3. PyMongo

首先,创建一个数据库连接对象

创建数据库连接对象有二种方式,分别是:多参数、字符串拼接

import pymongo

# 创建数据库连接对象的两种方式
# 方式一:多参数
self.client = pymongo.MongoClient(host='ip地址', port=27017, username="root", password="123456",
                                          authMechanism="SCRAM-SHA-1")
# 方式二:拼接
# self.client = pymongo.MongoClient('mongodb://root:123456@ip地址:27017/')

接着,通过数据库连接对象指定要操作的数据库和操作集合

比如:要操作数据库 temp 中的 students 集合

# 指定要操作的数据库:temp
self.db = self.client.temp

# 指定要操作集合students
self.collection_students = self.db.students

接着,我们来实现增删改查操作

1、新增

新增包含:新增单条数据和多条数据

单条数据插入对应的方法是:

insert_one(dict)

该方法的返回值类型为 InsertOneResult

通过 inserted_id 属性,可以获取插入数据的 _id 值

temp_data = {
    "id": "1",
    "name": "xag",
    "age": 18
}

# 1、直接调用集合的insert_one()方法插入数据(插入一条数据)
result = self.collection_students.insert_one(temp_data)

# 返回值为InsertOneResult,通过inserted_id属性获取_id的值
print(result.inserted_id)

多条数据插入对应的方法是:

insert_many([dict1,dict2...])

该方法的返回值类型为 InsertManyResult

通过 inserted_ids 属性,可以获取插入数据的 _id 属性值列表

# 2、插入多条数据-insert_many()
result = self.collection_students.insert_many([temp_data, temp_data2])

# 返回值为InsertManyResult,通过inserted_ids属性获取插入数据的_id列表值
print(result.inserted_ids)

2、查询

使用 PyMongo 查询 MongoDB 数据库,常用方法如下:

  • 通过某一个属性键值对,去查询一条记录 - find_one()

  • 通过 ObjectId 值去查询某一条记录 - find_one()

  • 通过某一个属性键值对,去查询多条记录 - find()

  • 通过大于、小于、等于等条件去比较查询

  • 正则匹配查询

前面 3 种查询方式,由于比较简单,直接给出实例:

def manage_query(self):
    """查询数据"""
    # 1、通过某个属性键值对,去查询一条记录 find_one()
    # 返回值为字典类型
    # {'_id': ObjectId('5f5c437cfe49fa9a16664179'), 'id': '1', 'name': 'xag', 'age': 18}
    result = self.collection_students.find_one({"name": "xag"})
    print(result)

    # 2、通过ObjectId值去查询某一条记录
    result = self.collection_students.find_one({"_id": ObjectId('5f5c437cfe49fa9a16664179')})
    print(result)

    # 3.1 查询多条记录 find()
    # 返回值为一个游标(生成器),pymongo.cursor.Cursor
    result_lists = self.collection_students.find({"name":"xag"})
    print(result_lists)
    for item in result_lists:
        print(item)

条件比较查询,包含:大于(

gt)、大于等于(
gte)、小于(
lt)、小于等于(
lte)、不等于(
ne)、在范围内(
in)、不在范围内($nin)

比如:查询年龄大于 18 岁的数据

# 3.2 条件比较查询,包含大于($gt)、大于等于($gte)、小于($lt)、小于等于($lte)、不等于($ne)、在范围内($in)、不在范围内($nin)
# 查询年龄大于18岁的记录
result = self.collection_students.find({'age': {'$gt': 18}})
for item in result:
    print(item)

正则匹配查询,包含:

  • $regex:匹配正则表达式

  • $exists:属性是否存在

  • $type:数据类型判断

  • $mod:数据模操作

  • $text:文本包含查询

  • $where:高级条件查询

比如,查询 name 值以 "xag" 开头的数据

# 正则匹配查询
results = self.collection_students.find({'name': {'$regex': '^xag.*'}})
for item in results:
    print(item)

关于查询更加复杂的功能可以参考:

https://docs.mongodb.com/manual/reference/operator/query/

3、更新

更新操作包含:更新一条记录和更新多条记录

其中,更新一条记录对应的方法是:

update_one(query,update_content)

参数包含:查询的条件、要修改的内容

# 1、修改一条记录 update_one(query,update_data)
# 方法中有两个参数,分别是:查询条件、要修改的内容
# 查询条件
query_condition = {"name": "xag"}
# 要修改的内容
update_content = {"$set": {"name": "星安果"}}
# 使用update_one() 方法进行更新一条记录
result = self.collection_students.update_one(query_condition, update_content)

通过返回的结果可以获取查询匹配的记录个数及影响的记录个数

# matched_count:匹配的记录个数
# modified_count:影响的记录个数
print(result.matched_count, result.modified_count)

更新多条记录对应的方法是:

update_many(query,update_content)

方法中的参数、返回值与修改单条记录类似

# 2、修改多条记录 update_many(query,update_data)
# 查询条件
query_condition = {"name": {"$regex": "^星.*"}}
# 要修改的内容
update_content = {"$set": {"name": "xag"}}
# 将文档中name以星开头的记录都设置为xag
result = self.collection_students.update_many(query_condition, update_content)
print(result)
print(result.matched_count, result.modified_count)

4、删除

删除同样包含:删除查询到的第一条记录、删除查询到的所有记录

分别对应的方法是:delete_one(query)、delete_many(query)

另外,在返回结果中可以获取到真实被删除的数目

def manage_remove(self):
    """
    删除操作
    :return:
    """
    # 1、删除查询到的第一条记录 delete_one()
    # result = self.collection_students.delete_one({'name': "xag2"})
    # print(result)
    # 删除的数目
    # print(result.deleted_count)

    # 2、删除多条记录 delete_many()
    result = self.collection_students.delete_many({'name': "xag"})
    print(result)
    # 删除的数目
    print(result.deleted_count)

5、计数和排名

常用的方法包含:

  • limit(num):限制返回的结果数量

  • skip(num):忽略 num 个元素,从 num + 1 个元素开始查看

  • count_documents():查看集合中所有的文档数量,也可以根据条件去查询满足的文档数量

  • sort():升序或者降序

def manage_count_and_sort(self):
    """
    计数和排序
    :return:
    """
    # 1、限制返回的结果数量 - limit()
    # result = self.collection_students.find().limit(2)
    # for item in result:
    #     print(item)

    # 2、偏移  skip()
    # 比如:忽略前面两个元素,从第3个元素开始查看
    # result = self.collection_students.find().skip(2)
    # print([result['name'] for result in result])

    # 3.1 查询出集合中所有的文档数量 count_documents()
    # result = self.collection_students.count_documents({})
    # print(result)

    # 3.2 根据条件去查询,然后判断结果数目
    # query_regex = {'name': {'$regex': '^xag.*'}}
    # result = self.collection_students.count_documents(query_regex)
    # print(result)

    # 4、排序 sort()
    # pymongo.ASCENDING:升序,DESCENDING:降序
    result = self.collection_students.find().sort('name', pymongo.DESCENDING)
    print([result['name'] for result in result])

4. Mongoengine

在使用 Mongoengine 操作 MongoDB 之前,需要先定义一个 Document 的子类

该子类对应 MongoDB 中的文档,内部加入的静态变量(包含:类型、长度等)对应数据库文档中的数据

from mongoengine import *

# Document的子类,对应文档对象
class Student(Document):
    name = StringField(required=True, max_length=500)
    age = IntField(required=True, default=18)
    create_time = DateTimeField(default=datetime.now)

    # 配置元数据
    # 指定集合为student
    meta = {'collection': 'student', 'strict': False}

利用 Mongoengine 内置的 connect() 方法,连接指定的数据库

# 连接数据库temp
def __init__(self):
    # 连接数据库
​    # 数据库名称:temp
    # auth方式:SCRAM-SHA-1
    result = connect('temp', host='ip地址', port=27017,
                     username='root', password='123456', authentication_source='admin',
                     auth

接着,我们来实现增删改查操作

1、新增

使用 Mongoengine 新增一条记录到数据库非常方便

只需要实例化一个文档对象,调用 save() 方法,即可以存储一条记录到数据库当中

def insert(self):
    """
    插入数据
    :return:
    """
    person = Student(name='xag2', age=20)
    person.save()

2、查询

常见的查询操作包含:

  • 查询集合中的所有记录

  • 查询第一条记录

  • 通过主键 _ID,来查询数据

  • 条件查询

对应的代码如下:

def query(self):
    """
    普通查询
    :return:
    """
    # 1、查看集合中所有数据
    # students = Student.objects.all()
    # print([item['name'] for item in students])

    # 2、查询第一条记录
    # student = Student.objects.first()
    # print(student.name, student.age, student.create_time)

    # 3、通过主键_ID来查询数据
    result = Student.objects.filter(pk="5f5c5b34f5b0c049707a1710").first()
    print(result.name, result.age, result.create_time)

    # 4、条件查询
    # 查询年龄在18-20岁的数据
    # __gte:大于等于;__lte:小于等于
    # 默认是升序,可以加一个:-,代表逆序
    # students = Student.objects(age__gte=18, age__lte=20).order_by('name')
    students = Student.objects(age__gte=18, age__lte=20).order_by('-name')
    # for item in students:
    #     print(item.name, item.age, item.create_time)

值得一提的是,Mongoengine 提供了关键字 Q 来实现高级查询

比如:查询 name 字段值为 xag,年龄为 18 岁的数据

def query_advance(self):
    """
    高级查询
​    :return:
    """
    # 查看name为xag,age为18的记录的第一条
    student = Student.objects(Q(name="xag") & Q(age=18)).first()
    print(student.name, student.age, student.create_time)

进阶操作可以参考:

https://docs.mongoengine.org/guide/querying.html

3、更新

Mongoengine 提供了 filter() 和 update() 两个方法,分别用于过滤待更新的数据,指定的更新内容

def update(self):
    """
    更新记录
    :return:
    """
    # 1、修改所有记录
    # 修改name为xag的年龄都减少1岁
    # 增加一岁:inc__age=1
    # 减少一岁:dec__age=1
    # Student.objects.filter(name="xag").update(dec__age=1)
    # Student.objects.filter(name="xag").update(inc__age=1)

    # name为xag,age小于18的的所有记录,更新为age=23
    # __lt:小于
    # __lte:小于等于
    # __gt:大于
    # __gte:大于等于
    # Student.objects.filter(name="xag", age__lt=18).update(age=23)
    # Student.objects.filter(age__lte=20).update(age=23)

如果只需要更改查询到的第一条记录,可以使用 update_one() 方法

# 2、修改一条记录
# 年龄减少5岁
Student.objects.filter(name='xag').update_one(dec__age=5)

4、删除

删除操作对应 delete() 方法

同样,可以利用 filter() 和 first() 方法限制要删除的范围

def delete(self):
    """
    删除数据
    :return:
    """
    # 1、删除查询到的第一条记录
    # Student.objects.filter(name="xag").first().delete()

    # 2、删除多条记录
    # Student.objects.filter(name="xag").delete()

    # 删除name值以xag开头的所有记录
    Student.objects.filter(name__startswith="xag").delete()

5.最后

本篇文章讲解了 Python 操作 MongoDB,最常用的两种使用方式

我已经将文中全部源码上传到后台,关注公众号「 AirPython 」后回复「 dball 」即可获得全部源码

如果你觉得文章还不错,请大家 点赞、分享、留言下,因为这将是我持续输出更多优质文章的最强动力!

推荐阅读

最全总结 | 聊聊 Python 数据处理全家桶(Mysql篇)

最全总结 | 聊聊 Python 数据处理全家桶(Sqlite篇)

最全总结 | 聊聊 Python 数据处理全家桶(Redis篇)

最全总结 | 聊聊 Python 数据处理全家桶(Memc篇)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342