Mongoengine:驾驭MongoDB数据的利器
Python操作MongoDB
MongoDB简介:
MongoDB是一种开源的文档型非关系型数据库,它不需要预定义数据结构,不需要固定的表结构,可以存储多种不同类型的数据,支持动态查询,通过使用JSON格式的BSON(Binary JSON)文档,使得存储数据非常灵活。MongoDB跨平台支持多种编程语言,包括C++、Python、Java等等,并且支持水平扩展,以及高可用性和自动容错能力。
以下是MongoDB的一些主要特点:
- 非关系型: MongoDB是非关系型数据库,不需要遵循传统的表格形式来存储数据,用户可以自由构造数据集。
- 面向文档型:MongoDB的每个记录都是一个文档对象,文档采用BSON(binary JSON)格式,BSON支持内嵌文档和列表类型等丰富的数据结构。
- 动态数据模型:MongoDB不需要固定的数据结构,文档可以根据需要动态添加字段,删除字段。
- 高可扩展性:MongoDB支持分布式存储,在多个服务器上进行数据复制、分片等操作,实现数据的高可用和高性能。
- 强大的查询功能: MongoDB支持查询操作,可以根据条件查询文档,支持聚合、排序、分页等一系列功能。
- 大数据量处理:MongoDB支持垂直扩展来处理大量数据集,如支持分片操作。
- 免费、开源:MongoDB是免费、开源的数据库,用户可以自由地使用、分发、扩展或修改MongoDB。
MongoDB由于自身特点的优越性,在Web应用、移动应用、社交网络、实时数据和物联网应用等地方得到了广泛应用。
使用Python连接MongoDB
在Python中连接MongoDB通常需要使用第三方库,最常用的是pymongo库。下面是一个使用pymongo库连接MongoDB的简单示例:
import pymongo# 连接 MongoDB
client = pymongo.MongoClient("mongodb://localhost:27017/")# 获取数据库实例
db = client["mydatabase"]# 获取集合实例
collection = db["mycollection"]# 插入一条文档
doc = {"name": "John", "age": 30}
res = collection.insert_one(doc)
print(res.inserted_id)# 查询文档
query = {"name": "John"}
res = collection.find(query)
for doc in res:print(doc)
在上面的示例中:
- 首先通过pymongo库中的MongoClient类创建了一个MongoDB客户端实例,指定了连接MongoDB服务器的地址和端口号。
- 然后通过客户端实例获取了MongoDB实例和集合实例,使用这些实例来执行对数据库和集合的操作。
- 最后插入一条文档并查询该文档。
在使用pymongo库操作MongoDB时,通常需要关注以下几个基本概念:
- MongoClient类:用于连接和管理MongoDB服务器,通过该类可以获取MongoDB实例和集合实例。
- MongoDatabase类:用于表示一个MongoDB数据库,可以通过客户端实例的索引方式获取MongoDB实例。
- MongoCollection类:用于表示一个MongoDB集合,每个集合代表数据库中的一个表格,可以通过数据库实例的方法获取集合实例。
- 文档(document):MongoDB中的基本存储单元,类似于数据库中的记录或行。文档是一种类似于JSON的结构,可以有不同的字段和值。
什么是orm框架
ORM (Object-Relational Mapping) 是一种常见的软件开发技术,旨在将关系数据库中的数据与应用程序中的对象进行映射和同步。ORM框架是实现ORM技术的软件工具,它可以自动地生成SQL语句,将数据库表与应用程序中的对象互相转换,并提供更高级别的数据访问功能。
ORM框架主要用于简化与数据库的交互,特别是在复杂数据模型和大量数据的情况下。ORM框架通过使用面向对象编程的方式来处理数据库记录,提供了对数据库的高级别抽象,消除了很多手动编写SQL语句的需求。这些框架通常提供的功能包括:
- 通过将实体类与数据库表进行映射,ORM框架可以自动创建或更新数据库表结构。
- 自动处理数据类型转换、SQL语句的拼接和执行,从而简化了常见的数据库操作。
- 提供了高级别的检索和查询功能,例如排序、分页和聚合查询等。
- 提供事务管理,从而确保数据一致性和完整性。
- 支持多种数据库,包括MySQL、PostgreSQL、Oracle和SQL Server等。
常用的ORM框架包括Hibernate、MyBatis、Spring Data JPA和Django ORM等。 各种ORM框架有其自己的特点和优点,需要根据项目需求和开发经验来选择合适的框架。
Python操作MongoDB的ORM框架
在Python中操作MongoDB数据库可以使用ORM框架。ORM(Object-Relational Mapping)是一种编程技术,它将Python对象和MongoDB文档映射起来,使得可以通过Python代码来操作MongoDB数据库,避免直接在代码中写MongoDB的原生查询语句。
以下是几个Python操作MongoDB的ORM框架:
- PyMongo
PyMongo是Python中最流行的MongoDB驱动程序之一,它提供了一个简单的API来操作MongoDB数据库。PyMongo不是一个完整的ORM框架,但它可以很方便地与Python对象进行交互,可以将Python对象转换成MongoDB文档,并将MongoDB文档转换成Python对象。
- MongoEngine
MongoEngine是一个比较流行的MongoDB ORM框架。它提供了一个高层次的API,并支持复杂的查询,如聚合查询、嵌套查询等。使用MongoEngine,您可以定义Python类,将其映射到MongoDB的集合,并使用Python代码来查询和操作MongoDB数据。
- Ming
Ming是一个Python编写的MongoDB ORM框架,它提供了大量的MongoDB特定的功能和查询API。Ming可以处理MongoDB数据库的基本操作,如插入、查询和更新,同时它也支持高级复杂查询。
- Tortoise-ORM
Tortoise-ORM是一个异步的Python ORM框架,它支持MongoDB数据库。Tortoise-ORM具有简单易用的API,并支持复杂的查询,如聚合查询和嵌套查询。与其他ORM框架不同,Tortoise-ORM采用异步编程模式,可以更好地处理并发请求。
以上是一些操作MongoDB的ORM框架,它们都可以通过简单的配置来连接MongoDB数据库,并提供多种操作API。选择合适的ORM框架取决于您的项目需求和个人喜好。
MongoEngine的使用
MongoEngine是一个Python ORM框架,专门用于与MongoDB数据库进行交互,并提供了更加Pythonic和便捷的方式来操作MongoDB数据库。MongoEngine旨在简化与MongoDB数据库的交互和管理,提供了更加友好的API来创建MongoDB文档(document)对象,并进行查询、更新、删除等操作。
在实际项目应用中,还可以使用MongoEngine提供的其他高级特性,例如聚合管道、嵌套文档、索引等。总的来说,MongoEngine提供了非常方便和易用的API来使用MongoDB数据库。
以下是MongoEngine的一些基本使用方法:
基本连接
首先需要安装MongoEngine,可以使用pip进行安装:
pip install mongoengine
连接MongoDB:
from mongoengine import connectconnect(db='mydb', host='localhost', port=27017)
定义MongoDB文档
MongoDB文档就是MongoDB中的一条记录,可以通过MongoEngine定义一个文档类来描述MongoDB文档的结构,并且文档类需要继承自mongoengine.Document
。
from mongoengine import Document, StringField, IntFieldclass User(Document):name = StringField(required=True)age = IntField()
上述代码定义了一个User类,它表示了一个MongoDB的文档数据集合的结构,包含了name和age两个字段,其中name字段必传。
插入数据
通过创建文档对象,可以将数据保存到数据库中。
user = User(name='Tom', age=18)
user.save()
也可以使用下面的方式实现:
User(name='Tom', age=18).save()
查询数据
查询可以使用MongoEngine提供的queryset
对象来实现。
查询所有的数据:
users = User.objects.all()
查询符合条件的数据:
user = User.objects(name='Tom', age=18).first()
更新数据
对于已存在的文档,可以使用update方法来更新数据。
# 查询并将Tom的年龄改为20
User.objects(name='Tom').update(age=20)
删除数据
删除文档可以使用delete方法。
User.objects(name='Tom').delete()
设置某列值唯一
在MongoEngine中,可以使用unique=True
参数设置模型中的字段值唯一。这将防止模型中指定的字段具有重复的值。例如,假设我们有一个名为User
的模型,并希望确保其中的email
字段值是唯一的,可以这样定义模型:
from mongoengine import Document, StringFieldclass User(Document):email = StringField(max_length=100, required=True, unique=True)name = StringField(max_length=50, required=True)password = StringField(max_length=100, required=True)
在上述代码中,unique=True
参数设置了email
字段的值必须唯一,因此如果有两个或多个用户尝试使用相同的电子邮件地址进行注册,MongoEngine将引发重复键错误。
需要注意的是,MongoDB在使用唯一索引时会忽略空值,因此如果在模型中添加了unique=True
参数,则必须确保该字段不为Null
或空字符串。否则,多个空值将被视为相同值,引发重复键错误。在这种情况下,可以添加另一个属性,如required=True
,以确保该字段不为空。
除了在字段级别上设置唯一性外,MongoEngine还可以在整个模型级别上设置唯一性。要在整个模型上设置唯一性,请使用meta
属性并指定unique
键。例如,如果我们希望确保User
模型中的每个用户具有唯一的姓名和电子邮件地址,可以这样定义模型:
from mongoengine import Document, StringFieldclass User(Document):email = StringField(max_length=100, required=True)name = StringField(max_length=50, required=True)meta = {'indexes': [{'fields': ['email'], 'unique': True},{'fields': ['name'], 'unique': True}]}
在上述代码中,我们在模型的meta
属性中指定了indexes
键的值。该值是一个列表,其中包含多个字典,用于指定要在模型中创建的索引。每个字典都使用fields
键指定要索引的字段,并使用unique
键指定该字段是否应该具有唯一性。因此,我们定义了两个索引,一个索引用于email
字段,另一个索引用于name
字段,并将它们都设置为唯一。
总之,使用unique=True
参数或在模型级别上使用indexes
选项,可以轻松地确保MongoEngine模型中的字段或模型本身的值是唯一的。
MongoEngine提供的嵌套文档
MongoEngine是一个Python的MongoDB 框架,提供了许多方便的操作MongoDB数据库的功能,其中之一就是支持嵌套文档。
嵌套文档是指在一个文档中嵌套了另一个文档,使得文档之间形成一定的层级结构,这样就可以更灵活地组织数据,同时也能够实现复杂的数据关系。
在MongoEngine中,定义一个嵌套文档和定义一个普通文档类似,只需要在字段上使用EmbeddedDocumentField类型即可。例如,定义一个嵌套在User文档中的Address文档:
from mongoengine import Document, EmbeddedDocument, StringField, EmbeddedDocumentFieldclass Address(EmbeddedDocument):street = StringField(required=True)city = StringField(required=True)state = StringField(required=True)class User(Document):name = StringField(required=True)address = EmbeddedDocumentField(Address)
可以看到,定义嵌套文档和普通文档的主要区别在于使用EmbeddedDocument类来定义嵌套文档,同时嵌套文档的定义需要在主文档中使用EmbeddedDocumentField类型来引用。
当使用MongoEngine进行数据库操作时,嵌套文档的操作与普通文档类似,只需要使用点号访问字段即可。例如,要获取一个用户的城市信息,可以如下面这样做:
user = User.objects(name='Alice').first()
city = user.address.city
还可以使用嵌套文档实现数组形式的数据存储。例如,以下定义将在主文档中使用一个列表来嵌套存储多个Address文档:
class User(Document):name = StringField(required=True)addresses = EmbeddedDocumentField(Address, multiple=True)
对于嵌套的列表类型,可以通过下标或迭代器访问每一个嵌套的文档,例如:
user = User.objects(name='Alice').first()# 访问第一个地址信息
first_address = user.addresses[0]# 遍历所有地址信息
for address in user.addresses:print(address.city)
在MongoDB中,嵌套文档的存储方式与关系型数据库的外键不同,嵌套文档是完全嵌套在主文档中的,因此适用于小型、高度相关的数据和文档频繁被一次性读取或更新的场景。同时,也需要注意使用嵌套文档时,嵌套层数不要过深,否则容易导致查询性能下降。
MongoEngine提供的聚合管道
MongoEngine是Python的一个MongoDB ODM库,它提供了一些用于聚合数据的工具。其中最常用的工具之一就是聚合管道(Aggregation Pipeline)。聚合管道是MongoDB中一种强大的聚合工具,允许您对文档进行基于多个阶段的处理,以生成分析结果。MongoEngine中的聚合管道利用MongoDB原生的聚合操作实现,可以实现复杂的聚合操作,例如分组、过滤、排序和限制等。
MongoEngine的聚合管道API类似于MongoDB聚合管道,它允许您使用流水线的方式组合多个操作步骤来处理数据。以下是MongoEngine提供的一些主要聚合管道:
- $project:选择文档的子集,只返回指定字段。可以对选择的字段进行处理、重新命名或排除。
- $match:对输入文档进行筛选,仅输出符合条件的文档。可以使用各种查询操作符构建复杂的条件。
- $group:将文档分组到一个集合中,并对每个集合执行聚合操作。
- $sort:将文档按指定字段进行排序。
- $limit:限制输出文档的数量。
- $skip:跳过指定数量的文档,以便进行分页操作。
- $unwind:将由数组或嵌套文档组成的字段进行拆分和展开。
- $lookup:实现左外连接操作,将一个集合中的文档与另一个集合中的文档进行关联。
通过使用这些操作,可以构建复杂的流水线来处理MongoDB中的文档,同时得出有用的分析结果。MongoEngine聚合管道提供了一个方便而强大的方式来使这些文档转换成有意义的数据。
以下是一些可以使用MongoEngine聚合管道执行的示例:
- 计算特定字段的总数:
from mongoengine import connect, Document, IntField
from mongoengine.aggregation import Aggregateconnect('test')class Person(Document):age = IntField()# 统计年龄总和
pipeline = [{'$group': {'_id': None, 'totalAge': {'$sum': '$age'}}},{'$project': {'_id': 0, 'totalAge': 1}}
]result = Person.aggregate(*pipeline)
for doc in result:print(doc.totalAge)
- 按字段分组并计算每组的平均值:
from mongoengine import connect, Document, StringField, IntField
from mongoengine.aggregation import Aggregateconnect('test')class Person(Document):name = StringField()age = IntField()# 计算每个名字的平均年龄
pipeline = [{'$group': {'_id': '$name', 'avgAge': {'$avg': '$age'}}},{'$project': {'_id': 0, 'name': '$_id', 'avgAge': 1}}
]result = Person.aggregate(*pipeline)
for doc in result:print(doc.name, doc.avgAge)
- 对数据进行排序和筛选后取前5个:
from mongoengine import connect, Document, StringField, IntField
from mongoengine.aggregation import Aggregateconnect('test')class Person(Document):name = StringField()age = IntField()# 获取年龄最大的5个人的名字和年龄
pipeline = [{'$sort': {'age': -1}},{'$limit': 5},{'$project': {'_id': 0, 'name': 1, 'age': 1}}
]result = Person.aggregate(*pipeline)
for doc in result:print(doc.name, doc.age)
聚合管道功能使得从MongoDB数据库中提取和处理数据变得更加方便和高效。使用MongoEngine的聚合管道,开发人员可以轻松地执行复杂的聚合操作,而不需要编写大量的代码来实现这些操作。
更多查询
1.使用时先声明一个继承自MongoEngine.Document的类
在类中声明一些属性,相当于创建一个用来保存数据的数据结构,即数据已类似数据结构的形式存入数据库中,通常把这样的一些类都存放在一个脚本中,作为应用的Model模块
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)users = Users.objects.all() #返回所有的文档对象列表
for u in users:print("name:",u.name,",age:",u.age)
2.保存文档
required:设置必须;
default:如果没有其他值给出使用指定的默认值
unique:确保集合中没有其他document有此字段的值相同
choices:确保该字段的值等于数组中的给定值之一
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)
user1 = Users(name='jack',age= 21
)
user1.save()
print(user1.name)
user1.name = 'jack2'
user1.save()
print(user1.name)
3.查询10=<年龄<30的,按姓名排列
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)
user_search = Users.objects(age__gte=10, age__lt=30).order_by('name')
for u in user_search:print("name:",u.name,",age:",u.age)
查询10=<年龄<30的,按姓名倒序
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)
user_search = Users.objects(age__gte=10, age__lt=30).order_by('-name')
for u in user_search:print("name:",u.name,",age:",u.age)
查询name=jack2
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)tmp = Users.objects(name="jack2")
for u in tmp:print("name:",u.name,",age:",u.age)
4.修改name=jack2 的age加1
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)
tmp = Users.objects(name="jack3").update(inc__age=1)
tmp = Users.objects(name="jack3")
for u in tmp:print("name:",u.name,",age:",u.age)
修改name=jack的age设为66
from mongoengine import *
connect('mydb', host='localhost', port=27017)
import datetime
class Users(Document):name = StringField(required=True, max_length=200)age = IntField(required=True)tmp = Users.objects(name="jack").update(set__age=66)
tmp = Users.objects(name="jack")
for u in tmp:print("name:",u.name,",age:",u.age)
高级查询
例如有时候你需要将约束条件进行与,或的操作。你可以使用mongoengine提供的 Q 类来实现,一个 Q 类代表了一个查询的一部分,里面的参数设置与你查询document的时候相同。建立一个复杂查询的时候,你需要用 & 或 | 操作符将 Q 对象连结起来,例子如下:
Post.objects(Q(name=“jack”) | Q(age=66))
查询相关操作符
ne – 不等于
lt – 小于
lte – 小于等于
gt – 大于
gte – 大于等于
not – 使其检查的反面,需要使用在其他操作符之前(e.g. Q(age__not__mod=5))
in – 值在list里面
nin – 值不在list里面
mod – value % x == y
all – list里面所有的值
size – 这个array的大小
exists – 存在这个值
#一下操作符在需要进行正则检查的时候是比较快捷的方法:
exact – 字符串型字段完全匹配这个值
iexact – 字符串型字段完全匹配这个值(大小写敏感)
contains – 字符串字段包含这个值
icontains –字符串字段包含这个值(大小写敏感)
startswith – 字符串字段由这个值开头
istartswith –字符串字段由这个值开头(大小写敏感)
endswith – 字符串字段由这个值结尾
iendswith –字符串字段由这个值结尾(大小写敏感)
match – 使你可以使用一整个document与数组进行匹配查询list
项目仓库看这里🤗:
https://github.com/w-x-x-w
https://gitee.com/w-_-x
博客文章看这里🤭:
https://blog.csdn.net/weixin_62650212
视频推送看这里🤤:
https://space.bilibili.com/1909782963