- Mongo引擎教程
- MongoEngine - 主页
- MongoEngine——MongoDB
- MongoEngine - MongoDB 指南针
- MongoEngine - 对象文档映射器
- MongoEngine - 安装
- MongoEngine - 连接到 MongoDB 数据库
- MongoEngine - 文档类
- MongoEngine - 动态模式
- MongoEngine - 字段
- MongoEngine - 添加/删除文档
- MongoEngine - 查询数据库
- MongoEngine - 过滤器
- MongoEngine - 查询运算符
- MongoEngine - 查询集方法
- MongoEngine - 排序
- MongoEngine - 自定义查询集
- MongoEngine - 索引
- MongoEngine - 聚合
- MongoEngine - 高级查询
- MongoEngine - 文档继承
- MongoEngine - 原子更新
- MongoEngine-Javascript
- MongoEngine-GridFS
- MongoEngine - 信号
- MongoEngine - 文本搜索
- MongoEngine - 扩展
- MongoEngine 有用资源
- MongoEngine - 快速指南
- MongoEngine - 有用的资源
- MongoEngine - 讨论
MongoEngine - 快速指南
MongoEngine——MongoDB
NoSQL 数据库在过去十年中越来越受欢迎。在当今的实时 Web 应用程序世界中,移动和嵌入式设备正在生成大量数据。传统的关系型数据库(如Oracle、MySQL等)不适合字符串。此类数据的处理也很困难,因为它们具有固定和预定义的模式,并且不可扩展。NOSQL数据库具有灵活的模式,并以分布式方式存储在大量的社区服务器上。
NOSQL 数据库根据数据组织进行分类。MongoDB 是一种流行的文档存储 NOSQL 数据库。MongoDB 数据库的基本组成部分称为文档。文档是以 JSON 格式存储的键值对的集合。集合中存储了多个文档。集合可以被视为类似于任何关系数据库中的表,文档可以被视为表中的行。但是,应该注意的是,由于 MongoDB 是无模式的,集合的每个文档中的键值对数量不必相同。
MongoDB由MongoDB Inc.开发。它是一个通用的、基于分布式文档的数据库。它有企业版和社区版。适用于 Windows 操作系统的最新社区版本可以从https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2012plus-4.2.6-signed.msi下载。
在您选择的文件夹中安装 MongoDB,并使用以下命令启动服务器 -
D:\mongodb\bin>mongod
服务器现在已准备好在端口 27017 接收传入连接请求。MongoDB 数据库存储在 bin/data 目录中。可以通过上述命令中的 –dbpath 选项更改此位置。
在另一个命令终端中,使用以下命令启动 MongoDB 控制台 -
D:\mongodb\bin>mongo
MongoDB 提示符类似于我们通常在 MySQL 或 SQLite 终端中看到的提示符。所有数据库操作(例如创建数据库、插入文档、更新和删除以及检索文档)都可以在控制台内完成。
E:\mongodb\bin>mongo
MongoDB shell version v4.0.6
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("0d848b11-acf7-4d30-83df-242d1d7fa693") }
MongoDB server version: 4.0.6
---
>
使用的默认数据库是 test。
> db Test
使用“use”命令,任何其他数据库都会设置为当前数据库。如果指定的数据库不存在,则创建新的数据库。
> use mydb switched to db mydb
请参阅我们关于 MongoDB 的详细教程:https://www.tutorialspoint.com/mongodb/index.htm。
MongoEngine - MongoDB 指南针
MongoDB 还开发了一个 GUI 工具来处理 MongoDB 数据库。它被称为 MongoDB Compass。它是一个方便的工具,无需手动编写查询即可执行所有 CRUD 操作。它有助于许多活动,例如索引、文档验证等。
从https://www.mongodb.com/download-center/compass下载社区版 MongoDB Compass并启动MongoDBCompassCommunity.exe(在启动 Compass 之前确保 MongoDB 服务器正在运行)。通过提供正确的主机和端口号连接到本地服务器。
当前可用的所有数据库将列出如下 -
单击+按钮(显示在左面板底部)创建新数据库。
从列表中选择数据库名称并选择一个集合,如下所示 -
您可以直接添加文档或从 CSV 或 JSON 文件导入。
从“添加数据”下拉列表中选择“插入文档”。
添加的文档将以 JSON、列表或表格形式显示 -
请注意,就像关系数据库中的表有一个主键一样,MongoDB 数据库中的文档有一个自动生成的名为“ _id ”的特殊键。
MongoDB Inc. 提供了用于连接 MongoDB 数据库的 Python 驱动程序。它称为PyMongo,其用法类似于标准 SQL 查询。
安装 PyMongo 模块后,我们需要 MongoClient 类的对象来与 MongoDB 服务器交互。
<<< from pymongo import MongoClient <<< client=MongoClient()
使用以下语句创建新数据库 -
db=client.mydatabase
该数据库上的 CRUD 操作是通过 insert_one() (或 insert_many())、find()、update() 和 delete() 等方法执行的。PyMongo 库的详细讨论可参见https://www.tutorialspoint.com/python_data_access/python_mongodb_introduction.htm。
然而,Python的用户定义对象不能存储在数据库中,除非转换为MongoDB的数据类型。这就是我们需要MongoEngine库的地方。
MongoEngine - 对象文档映射器
MongoDB 是一个基于文档的数据库。每个文档都是类似 JSON 的字段和值表示。MongoDB 中的文档大致相当于 RDBMS 表中的一行(MongoDB 相当于表是 Collection)。尽管 MongoDB 不强制执行任何预定义模式,但文档中的字段对象具有特定的数据类型。MongoDB 数据类型与 Python 的主要数据类型非常相似。如果必须存储 Python 用户定义类的对象,则必须手动将其属性解析为等效的 MongoDB 数据类型。
MongoEngine 在 PyMongo 上提供了一个方便的抽象层,并将 Document 类的每个对象映射到 MongoDB 数据库中的文档。MongoEngine API由Hary Marr于2013年8月开发。MongoEngine的最新版本是0.19.1。
MongoEngine 之于 MongoDB 就像 SQLAlchemy 之于 RDBMS 数据库。MongoEngine 库提供了一个 Document 类,用作定义自定义类的基础。该类的属性构成了 MongoDB 文档的字段。Document 类定义了执行 CRUD 操作的方法。在后续主题中,我们将学习如何使用它们。
MongoEngine - 安装
要使用 MongoEngine,您需要已经安装了 MongoDB,并且 MongoDB 服务器应该按照前面所述运行。
安装 MongoEngine 最简单的方法是使用 PIP 安装程序。
pip install mongoengine
如果您的Python安装没有安装Setuptools,您必须从https://github.com/MongoEngine/mongoengine下载MongoEngine并运行以下命令 -
python setup.py install
MongoEngine 有以下依赖项 -
pymongo>=3.4
六>=1.10.0
dateutil>=2.1.0
Pillow>=2.0.0
要验证安装是否正确,请运行导入命令并检查版本,如下所示 -
>>> import mongoengine >>> mongoengine.__version__ '0.19.1'
连接到 MongoDB 数据库
如前所述,您应该首先使用 mongod 命令启动 MongoDB 服务器。
MongoEngine 提供 connect() 函数来连接到正在运行的 mongodb 服务器实例。
从 mongoengine 导入连接 连接('mydata.db')
默认情况下,MongoDB 服务器在本地主机和端口 27017 上运行。要进行自定义,您应该为 connect() 提供主机和端口参数 -
连接('mydata.db',主机='192.168.1.1',端口=12345)
如果数据库需要身份验证,则应提供其凭据,例如用户名、密码和authentication_source 参数。
连接('mydata.db',用户名='user1',密码='***',authentication_source='admin')
MongoEngine 还支持 URI 样式连接而不是 IP 地址。
连接('mydata.db',host='mongodb://localhost/database_name')
connect() 函数还有另一个可选参数,称为replicaset。MongoDB 是一个分布式数据库。存储在一台服务器中的数据通常会复制到许多服务器实例中,以确保高可用性。MongoDB 中的副本集是一组维护相同数据集的 mongod 进程。副本集是所有生产部署的基础。
连接(主机='mongodb://localhost/dbname?replicaSet=rs-name')
以下副本集方法定义如下:
| rs.add() | 将成员添加到副本集。 |
| rs.conf() | 返回副本集配置文档。 |
| rs.freeze() | 防止当前成员在一段时间内寻求当选为主要成员。 |
| rs.initiate() | 初始化一个新的副本集。 |
| rs.reconfig() | 通过应用新的副本集配置对象来重新配置副本集。 |
| rs.remove() | 从副本集中删除成员。 |
MongoEngine还允许连接多个数据库。您需要为每个数据库提供唯一的别名。例如,以下代码将 Python 脚本连接到两个 MongoDB 数据库。
connect(alias='db1', db='db1.db') connect(alias='db2', db='db2.db')
MongoEngine - 文档类
MongoEngine 被称为 ODM(对象文档映射器)。MongoEngine 定义了一个 Document 类。这是一个基类,其继承类用于定义存储在 MongoDB 数据库中的文档集合的结构和属性。该子类的每个对象在数据库中形成集合中的文档。
此 Document 子类中的属性是各种 Field 类的对象。以下是典型文档类的示例 -
from mongoengine import *
class Student(Document):
studentid = StringField(required=True)
name = StringField(max_length=50)
age = IntField()
def _init__(self, id, name, age):
self.studentid=id,
self.name=name
self.age=age
这看起来类似于 SQLAlchemy ORM 中的模型类。默认情况下,数据库中Collection的名称是Python类的名称,并将其名称转换为小写。但是,可以在 Document 类的元属性中指定不同的集合名称。
meta={collection': 'student_collection'}
现在声明此类的对象并调用 save() 方法将文档存储在数据库中。
s1=Student('A001', 'Tara', 20)
s1.save()
MongoEngine - 动态模式
MongoDB 数据库的优点之一是它支持动态模式。要创建支持动态架构的类,请将其从 DynamicDocument 基类创建子类。以下是具有动态模式的 Student 类 -
>>> class student(DynamicDocument): ... name=StringField()
第一步是像以前一样添加第一个文档。
>>> s1=student()
>>> s1.name="Tara"
>>> connect('mydb')
>>> s1.save()
现在向第二个文档添加另一个属性并保存。
>>> s2=student() >>> setattr(s2,'age',20) >>> s2.name='Lara' >>> s2.save()
在数据库中,学生集合将显示两个具有动态模式的文档。
文档类的元字典可以通过指定 max_documents 和 max_size 来使用 Capped Collection。
max_documents - 允许存储在集合中的最大文档数。
max_size - 集合的最大大小(以字节为单位)。max_size 之前由 MongoDB 内部和 mongoengine 向上舍入为 256 的下一个倍数。
如果未指定 max_size 而指定了 max_documents,则 max_size 默认为 10485760 字节 (10MB)。
Document 类的其他参数列出如下 -
| 物体 | 在访问时延迟创建的 QuerySet 对象。 |
| 级联保存() | 递归保存文档上的所有引用和通用引用。 |
| 干净的() | 用于在运行验证之前进行文档级数据清理的挂钩。 |
| 创建索引() | 如果需要,创建给定的索引。 |
| drop_collection() | 从数据库中删除与此文档类型关联的整个集合。 |
| from_json() | 将 json 数据转换为 Document 实例。 |
| 调整() | 对数据库中的文档执行Atomics更新,并使用更新后的版本重新加载文档对象。 |
| PK | 获取主键。 |
| 节省() | 将文档保存到数据库。如果文档已经存在,则更新该文档,否则创建该文档。返回保存的对象实例。 |
| 删除() | 从数据库中删除当前文档。 |
| 插入() | 执行批量插入操作。 |
MongoEngine - 字段
MongoEngine 文档类具有一个或多个属性。每个属性都是 Field 类的一个对象。BaseField 是基类或所有字段类型。BaseField 类构造函数具有以下参数 -
BaseField(db_field,必填,默认,唯一,主键)
db_field表示数据库字段的名称。
required 参数决定该字段的值是否为必填项,默认为 false。
默认参数包含该字段的默认值
unique参数默认为 false 。如果您希望此字段对于每个文档都具有唯一值,则设置为 true。
Primary_key参数默认为 false 。True 使该字段成为主键。
有许多从 BaseField 派生的 Field 类。
数字字段
IntField(32 位整数)、LongField(64 位整数)、FloatField(浮点数)字段构造函数具有 min_value 和 max_value 参数。
还有DecimalField类。该字段对象的值是一个浮点数,其精度可以指定。以下参数是为 DecimalField 类定义的 -
DecimalField(最小值、最大值、force_string、精度、舍入)
| 最小值 | 指定最小可接受值 |
| 最大值 | 指定字段可以具有的最大值 |
| 强制字符串 | 如果为 True,则该字段的值存储为字符串 |
| 精确 | 将浮动表示形式限制为位数 |
| 四舍五入 | 根据以下预定义常量对数字进行舍入:decimal.ROUND_CEILING(向无穷大)decimal.ROUND_DOWN(向零)decimal.ROUND_FLOOR(向-无穷大)decimal.ROUND_HALF_DOWN(向最接近的关系趋向零)decimal.ROUND_HALF_EVEN(向最接近的关系)到最接近的偶数)decimal.ROUND_HALF_UP(到最接近的且远离零的关系)decimal.ROUND_UP(远离零)decimal.ROUND_05UP(如果四舍五入到零后的最后一位数字是0或5,则远离零;否则朝向零) |
文本字段
StringField 对象可以存储任何 Unicode 值。您可以在构造函数中指定字符串的 min_length 和 max_length。URLField对象是一个 StringField,能够将输入验证为 URL。EmailField验证字符串是否为有效的电子邮件表示形式。
StringField(max-length, min_length) URLField(url_regex) EmailField(domain_whiltelist, allow_utf8_user, allow_ip_domain)
domain_whitelist 参数包含您不支持的无效域的列表。如果设置为 True,allow_utf8_user 参数允许字符串包含 UTF8 字符作为电子邮件的一部分。allowed_ip_domain 参数默认为 false,但如果为 true,则可以是有效的 IPV4 或 IPV6 地址。
以下示例使用数字和字符串字段 -
from mongoengine import *
connect('studentDB')
class Student(Document):
studentid = StringField(required=True)
name = StringField()
age=IntField(min_value=6, max-value=20)
percent=DecimalField(precision=2)
email=EmailField()
s1=Student()
s1.studentid='001'
s1.name='Mohan Lal'
s1.age=20
s1.percent=75
s1.email='mohanlal@gmail.com'
s1.save()
执行上述代码时,学生集合显示如下文档 -
列表字段
这种类型的字段包装任何标准字段,从而允许将多个对象用作数据库中的列表对象。该字段可以与ReferenceField一起使用来实现一对多关系。
上面示例中的学生文档类修改如下 -
from mongoengine import *
connect('studentDB')
class Student(Document):
studentid = StringField(required=True)
name = StringField(max_length=50)
subjects = ListField(StringField())
s1=Student()
s1.studentid='A001'
s1.name='Mohan Lal'
s1.subjects=['phy', 'che', 'maths']
s1.save()
添加的文档以 JSON 格式显示,如下 -
{
"_id":{"$oid":"5ea6a1f4d8d48409f9640319"},
"studentid":"A001",
"name":"Mohan Lal",
"subjects":["phy","che","maths"]
}
字典域
DictField 类的对象存储一个Python 字典对象。这也将存储在相应的数据库字段中。
我们将上面示例中的 ListField 的类型更改为 DictField。
from mongoengine import *
connect('studentDB')
class Student(Document):
studentid = StringField(required=True)
name = StringField(max_length=50)
subjects = DictField()
s1=Student()
s1.studentid='A001'
s1.name='Mohan Lal'
s1.subjects['phy']=60
s1.subjects['che']=70
s1.subjects['maths']=80
s1.save()
数据库中的文档显示如下 -
{
"_id":{"$oid":"5ea6cfbe1788374c81ccaacb"},
"studentid":"A001",
"name":"Mohan Lal",
"subjects":{"phy":{"$numberInt":"60"},
"che":{"$numberInt":"70"},
"maths":{"$numberInt":"80"}
}
}
参考字段
MongoDB 文档可以使用此类字段存储对另一个文档的引用。这样,我们就可以像 RDBMS 中那样实现 join。ReferenceField 构造函数使用其他文档类的名称作为参数。
class doc1(Document): field1=StringField() class doc2(Document): field1=StringField() field2=ReferenceField(doc1)
在以下示例中,StudentDB 数据库包含两个文档类:学生和教师。学生类的文档包含对教师类对象的引用。
from mongoengine import *
connect('studentDB')
class Teacher (Document):
tid=StringField(required=True)
name=StringField()
class Student(Document):
sid = StringField(required=True)
name = StringField()
tid=ReferenceField(Teacher)
t1=Teacher()
t1.tid='T1'
t1.name='Murthy'
t1.save()
s1=Student()
s1.sid='S1'
s1.name='Mohan'
s1.tid=t1
s1.save()
运行上面的代码并在 Compass GUI 中验证结果。在 StudentDB 数据库中创建对应于两个文档类的两个集合。
添加的教师文档如下 -
{
"_id":{"$oid":"5ead627463976ea5159f3081"},
"tid":"T1",
"name":"Murthy"
}
学生文件显示内容如下 -
{
"_id":{"$oid":"5ead627463976ea5159f3082"},
"sid":"S1",
"name":"Mohan",
"tid":{"$oid":"5ead627463976ea5159f3081"}
}
请注意,Student 文档中的 ReferenceField 存储了相应 Teacher 文档的 _id。当访问时,Student 对象会自动转换为引用,并在访问相应的 Teacher 对象时取消引用。
要添加对正在定义的文档的引用,请使用“self”而不是其他文档类作为 ReferenceField 的参数。可能会注意到,就文档检索而言,使用 ReferenceField 可能会导致性能不佳。
ReferenceField 构造函数还有一个可选参数:reverse_delete_rule。它的值决定了当引用的文档被删除时要做什么。
可能的值如下 -
DO_NOTHING (0) - 不执行任何操作(默认)。
NULLIFY (1) - 将引用更新为 null。
CASCADE (2) - 删除与参考相关的文档。
DENY (3) - 阻止删除引用对象。
PULL (4) - 从引用列表字段中拉出引用
您可以使用引用列表实现一对多关系。假设学生文档必须与一个或多个教师文档相关,则 Student 类必须具有 ReferenceField 实例的 ListField。
从 mongoengine 导入 * 连接('studentDB') 班主任(文件): tid=StringField(必需=True) 名称=字符串字段() 班级学生(文件): sid = StringField(必需=True) 名称 = 字符串字段() tid=ListField(ReferenceField(老师)) t1=老师() t1.tid='T1' t1.name='穆蒂' t1.保存() t2=老师() t2.tid='T2' t2.name='萨克塞纳' t2.保存() s1=学生() s1.sid='S1' s1.name='莫罕' s1.tid=[t1,t2] s1.save()
在 Compass 中验证上述代码的结果时,您会发现学生文档引用了两个教师文档 -
教师收藏
{
"_id":{"$oid":"5eaebcb61ae527e0db6d15e4"},
"tid":"T1","name":"Murthy"
}
{
"_id":{"$oid":"5eaebcb61ae527e0db6d15e5"},
"tid":"T2","name":"萨克塞纳"
}
学生收藏
{
"_id":{"$oid":"5eaebcb61ae527e0db6d15e6"},
"sid":"S1","name":"莫罕",
"tid":[{"$oid":"5eaebcb61ae527e0db6d15e4"},{"$oid":"5eaebcb61ae527e0db6d15e5"}]
}
日期时间字段
DateTimeField 类的实例允许 MongoDB 数据库中的日期格式的数据。MongoEngine 寻找 Python-DateUtil 库来解析适当日期格式的数据。如果当前安装中不可用,则使用内置时间模块的 time.strptime() 函数表示日期。该类型字段的默认值是当前日期时间实例。
动态场
该字段可以处理不同类型的数据。这种类型的字段由DynamicDocument类内部使用。
图像场
这种类型的字段对应于文档中可以存储图像文件的字段。此类的构造函数可以接受 size 和thumbnail_size 参数(均以像素大小表示)。
MongoEngine - 添加/删除文档
我们已经使用 Document 类的 save() 方法在集合中添加文档。save() 方法可以借助以下参数进一步自定义 -
| 强制插入 | 默认值为 False,如果设置为 True 则不允许更新现有文档。 |
| 证实 | 验证文件;设置为 False 以跳过。 |
| 干净的 | 调用文档清理方法,验证参数应为 True。 |
| 写关注 | 将用作生成的 getLastError 命令的选项。例如,save(..., write_concern={w: 2, fsync: True}, ...) 将等待,直到至少两个服务器记录了写入,并将在主服务器上强制进行 fsync。 |
| 级联 | 设置级联保存的标志。您可以通过在文档 __meta__ 中设置“cascade”来设置默认值。 |
| 级联_kwargs | 要传递的可选关键字参数抛出到级联保存。相当于级联=True。 |
| _refs | 级联保存中使用的已处理引用的列表 |
| 保存条件 | 仅当数据库中的匹配记录满足条件时才执行保存。如果不满足条件则引发操作错误 |
| 信号_kwargs | 要传递给信号调用的 kwargs 字典。 |
您可以在调用 save() 之前设置用于验证文档的清理规则。通过提供自定义clean()方法,您可以进行任何预验证/数据清理。
class MyDocument(Document):
...
...
def clean(self):
if <condition>==True:
msg = 'error message.'
raise ValidationError(msg)
请注意,仅当验证打开且调用 save() 时才会调用 Cleaning。
Document 类还具有insert()方法来执行批量插入。它有以下参数 -
| 文档或文档 | 要插入的文档或文档列表 |
| 批量加载 | 如果为 True,则返回文档实例的列表 |
| 写关注 | 额外的关键字参数被传递给 insert() ,它将用作结果 getLastError 命令的选项。 |
| 信号_kwargs | (可选)要传递给信号调用的 kwargs 字典 |
如果文档包含任何 ReferenceField 对象,则默认情况下 save() 方法不会保存对这些对象的任何更改。如果您还希望保存所有引用,请注意每个保存都是一个单独的查询,然后将cascade 作为 True 传递给 save 方法将级联任何保存。
通过调用delete() 方法,从文档集合中删除文档非常简单。请记住,只有先前保存过文档,它才会生效。delete() 方法有以下参数 -
| 信号_kwargs | (可选)要传递给信号调用的 kwargs 字典。 |
| 写关注 | 额外的关键字参数被向下传递,这些参数将用作生成的 getLastError 命令的选项。 |
要从数据库中删除整个集合,请使用drop_collection()方法。它从数据库中删除与此文档类型关联的整个集合。如果文档没有集合集(如果它是抽象的,则该方法会引发OperationError)。
文档类中的modify ()方法对数据库中的文档执行Atomics更新并重新加载其更新版本。如果文档已更新,则返回 True;如果数据库中的文档与查询不匹配,则返回 False。请注意,如果该方法返回 True,则对文档所做的所有未保存的更改都将被拒绝。
参数
| 询问 | 仅当数据库中的文档与查询匹配时才会执行更新 |
| 更新 | Django 风格的更新关键字参数 |
MongoEngine - 查询数据库
connect() 函数返回一个 MongoClient 对象。使用该对象可用的list_database_names()方法,我们可以检索服务器上的数据库数量。
from mongoengine import *
con=connect('newdb')
dbs=con.list_database_names()
for db in dbs:
print (db)
还可以使用 list_collection_names() 方法获取数据库中的集合列表。
collections=con['newdb'].list_collection_names() for collection in collections: print (collection)
如前所述,Document 类具有对象属性,可以访问与数据库关联的对象。
newdb 数据库有一个与下面的 Document 类相对应的产品集合。为了获取所有文档,我们使用对象属性,如下所示 -
from mongoengine import *
con=connect('newdb')
class products (Document):
ProductID=IntField(required=True)
Name=StringField()
price=IntField()
for product in products.objects:
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
输出
ID: 1 Name: Laptop Price: 25000 ID: 2 Name: TV Price: 50000 ID: 3 Name: Router Price: 2000 ID: 4 Name: Scanner Price: 5000 ID: 5 Name: Printer Price: 12500
MongoEngine - 过滤器
对象属性是一个查询集管理器。它在访问时创建并返回一个 QuerySet。可以借助字段名称作为关键字参数来对查询进行过滤。例如,在上面的产品集合中,要打印产品名称为“TV”的文档的详细信息,我们使用 Name 作为关键字参数。
for product in products.objects(Name='TV'):
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
您可以使用 QuerySet 对象的 filter 方法将过滤器应用于查询。以下代码片段还返回 name='TV' 的产品详细信息。
qset=products.objects
for product in qset.filter(Name='TV'):
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
MongoEngine - 查询运算符
除了用于检查相等性的 = 运算符之外,MongoEngine 中还定义了以下逻辑运算符。
| 讷 | 不等于 |
| 其 | 少于 |
| LTE | 小于或等于 |
| GT | 比...更棒 |
| 通用电气 | 大于或等于 |
| 不是 | 否定标准检查,可以在其他运算符之前使用 |
| 在 | 值在列表中 |
| 宁 | 值不在列表中 |
| 模组 | value % x == y,其中 x 和 y 是两个提供的值 |
| 全部 | 提供的值列表中的每个项目都在数组中 |
| 尺寸 | 数组的大小是 |
| 存在 | 字段值存在 |
这些运算符必须附加到带有双下划线 __ 的字段名称。
要使用大于 (gt) 运算符,请使用以下格式 -
#using greater than operator
for product in products.objects(price__gt=10000):
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
输出
ID: 1 Name: Laptop Price: 25000 ID: 2 Name: TV Price: 50000 ID: 5 Name: Printer Price: 12500
in 运算符类似于 Python 的 in 运算符。对于与列表中的名称匹配的产品名称,使用以下代码 -
for product in products.objects(Name__in=['TV', 'Printer']):
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
输出
ID: 2 Name: TV Price: 50000 ID: 5 Name: Printer Price: 12500
您可以使用以下运算符作为正则表达式的快捷方式,以将过滤器应用于查询 -
| 精确的 | 字符串字段与值完全匹配 |
| 精确的 | 字符串字段与值完全匹配(不区分大小写) |
| 包含 | 字符串字段包含值 |
| 图标包含 | 字符串字段包含值(不区分大小写) |
| 以。。开始 | 字符串字段以值开头 |
| 开始于 | 字符串字段以值开头(不区分大小写) |
| 以。。结束 | 字符串字段以值结尾 |
| 朋友 | 字符串字段以值结尾(不区分大小写) |
| 匹配 | 执行 $elemMatch 以便您可以匹配数组中的整个文档 |
例如,以下代码打印名称中包含“o”的名称的产品详细信息 -
for product in products.objects(Name__contains='o'):
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
输出
ID: 1 Name: Laptop Price: 25000 ID: 3 Name: Router Price: 2000
在字符串查询的另一个示例中,以下代码显示以“er”结尾的名称 -
for product in products.objects(Name__endswith='er'):
print ('ID:',product.ProductID, 'Name:',product.Name, 'Price:',product.price)
输出
ID: 3 Name: Router Price: 2000 ID: 4 Name: Scanner Price: 5000 ID: 5 Name: Printer Price: 12500
MongoEngine - 查询集方法
QuerySet 对象拥有以下用于查询数据库的有用方法。
第一的()
返回满足查询的第一个文档。以下代码将返回产品集合中价格 < 20000 的第一个文档。
qset=products.objects(price__lt=20000)
doc=qset.first()
print ('Name:',doc.Name, 'Price:',doc.price)
输出
Name: Router Price: 2000
排除()
这将导致提到的字段从查询集中排除。这里,Document类的to_json()方法用于获取Document的JSON化版本。ProductID 字段不会出现在结果中。
for product in products.objects.exclude('ProductID'):
print (product.to_json())
输出
{"_id": {"$oid": "5c8dec275405c12e3402423c"}, "Name": "Laptop", "price": 25000}
{"_id": {"$oid": "5c8dec275405c12e3402423d"}, "Name": "TV", "price": 50000}
{"_id": {"$oid": "5c8dec275405c12e3402423e"}, "Name": "Router", "price": 2000}
{"_id": {"$oid": "5c8dec275405c12e3402423f"}, "Name": "Scanner", "price": 5000}
{"_id": {"$oid": "5c8dec275405c12e34024240"}, "Name": "Printer", "price": 12500}
字段()
使用此方法可以操作要在查询集中加载哪些字段。使用字段名称作为关键字参数,并设置为 1 表示包含,0 表示排除。
for product in products.objects.fields(ProductID=1,price=1): print (product.to_json())
输出
{"_id": {"$oid": "5c8dec275405c12e3402423c"}, "ProductID": 1, "price": 25000}
{"_id": {"$oid": "5c8dec275405c12e3402423d"}, "ProductID": 2, "price": 50000}
{"_id": {"$oid": "5c8dec275405c12e3402423e"}, "ProductID": 3, "price": 2000}
{"_id": {"$oid": "5c8dec275405c12e3402423f"}, "ProductID": 4, "price": 5000}
{"_id": {"$oid": "5c8dec275405c12e34024240"}, "ProductID": 5, "price": 12500}
在 fields() 方法中将字段关键字参数设置为 0 的工作方式与 except() 方法类似。
for product in products.objects.fields(price=0): print (product.to_json())
输出
{"_id": {"$oid": "5c8dec275405c12e3402423c"}, "ProductID": 1, "Name": "Laptop"}
{"_id": {"$oid": "5c8dec275405c12e3402423d"}, "ProductID": 2, "Name": "TV"}
{"_id": {"$oid": "5c8dec275405c12e3402423e"}, "ProductID": 3, "Name": "Router"}
{"_id": {"$oid": "5c8dec275405c12e3402423f"}, "ProductID": 4, "Name": "Scanner"}
{"_id": {"$oid": "5c8dec275405c12e34024240"}, "ProductID": 5, "Name": "Printer"}
仅有的()
该方法的效果与 fields() 方法类似。仅与关键字参数对应的字段才会出现在查询集中。
for product in products.objects.only('Name'):
print (product.to_json())
输出
{"_id": {"$oid": "5c8dec275405c12e3402423c"}, "Name": "Laptop"}
{"_id": {"$oid": "5c8dec275405c12e3402423d"}, "Name": "TV"}
{"_id": {"$oid": "5c8dec275405c12e3402423e"}, "Name": "Router"}
{"_id": {"$oid": "5c8dec275405c12e3402423f"}, "Name": "Scanner"}
{"_id": {"$oid": "5c8dec275405c12e34024240"}, "Name": "Printer"}
和()
此方法计算查询集中给定字段的总和。
平均的()
该方法计算查询集中给定字段的平均值。
avg=products.objects.average('price')
ttl=products.objects.sum('price')
print ('sum of price field',ttl)
print ('average of price field',avg)
输出
sum of price field 94500 average of price field 18900.0
MongoEngine - 排序
QuerySet的order_by()函数用于以排序的方式获取查询结果。用法如下 -
Qset.order_by(‘fieldname’)
默认情况下,排序顺序为升序。对于降序排列,请在字段名称后附加 - 号。例如,要按升序获取价格明智的列表 -
from mongoengine import *
con=connect('newdb')
class products (Document):
ProductID=IntField(required=True)
company=StringField()
Name=StringField()
price=IntField()
for product in products.objects.order_by('price'):
print ("Name:{} company:{} price:{}".format(product.Name, product.company, product.price))
输出
Name:Router company:Iball price:2000 Name:Scanner company:Cannon price:5000 Name:Printer company:Cannon price:12500 Name:Laptop company:Acer price:25000 Name:TV company:Philips price:31000 Name:Laptop company:Dell price:45000 Name:TV company:Samsung price:50000
以下代码将以名称降序获取列表 -
for product in products.objects.order_by('-Name'):
print ("Name:{} company:{} price:{}".format(product.Name, product.company, product.price))
输出
Name:TV company:Samsung price:50000 Name:TV company:Philips price:31000 Name:Scanner company:Cannon price:5000 Name:Router company:Iball price:2000 Name:Printer company:Cannon price:12500 Name:Laptop company:Acer price:25000 Name:Laptop company:Dell price:45000
您还可以对多个字段进行排序。此代码将为您提供按公司升序排列的价目表。
for product in products.objects.order_by('company','price'):
print ("Name:{} company:{} price:{}".format(product.Name, product.company, product.price))
输出
Name:Laptop company:Acer price:25000 Name:Scanner company:Cannon price:5000 Name:Printer company:Cannon price:12500 Name:Laptop company:Dell price:45000 Name:Router company:Iball price:2000 Name:TV company:Philips price:31000 Name:TV company:Samsung price:50000
MongoEngine - 自定义查询集
默认情况下,文档类上的对象属性返回一个查询集,而不应用任何过滤器。但是,您可以在修改查询集的文档上定义类方法。这样的方法应该接受两个参数 - doc_cls 和 queryset,并且需要用 queryset_manager() 进行修饰才能被识别。
@queryset_manager
def qry_method(docs_cls,queryset):
….
----
在下面的示例中,名为 products 的文档类具有一个 由 @queryset_manager 修饰的昂贵_prods() 方法。该方法本身对查询集应用过滤器,以便仅返回价格 >20000 的对象。此方法现在是默认文档查询,产品类的对象属性返回过滤后的文档。
from mongoengine import *
con=connect('newdb')
class products (Document):
ProductID=IntField(required=True)
company=StringField()
Name=StringField()
price=IntField()
@queryset_manager
def expensive_prods(docs_cls,queryset):
return queryset.filter(price__gt=20000)
for product in products.expensive_prods():
print ("Name:{} company:{} price:{}".format(product.Name, product.company, product.price))
输出
Name:Laptop company:Acer price:25000 Name:TV company:Samsung price:50000 Name:TV company:Philips price:31000 Name:Laptop company:Dell price:45000
如果您希望自定义过滤文档的方法,请首先声明 QuerySet 类的子类,并将其用作元字典中的 queryset_class 属性的值。
下面的示例使用 MyQuerySet 类作为自定义查询集的定义。此类中的 myqrymethod() 过滤名称字段以“er”结尾的文档。在products类中,meta属性指的是该queryset子类用作queryset_class属性的值。
from mongoengine import *
con=connect('newdb')
class MyQuerySet(QuerySet):
def myqrymethod(self):
return self.filter(Name__endswith='er')
class products (Document):
meta = {'queryset_class': MyQuerySet}
ProductID=IntField(required=True)
company=StringField()
Name=StringField()
price=IntField()
for product in products.objects.myqrymethod():
print ("Name:{} company:{} price:{}".format(product.Name, product.company, product.price))
输出
Name:Router company:Iball price:2000 Name:Scanner company:Cannon price:5000 Name:Printer company:Cannon price:12500
MongoEngine - 索引
索引集合可以加快查询处理速度。默认情况下,每个集合都会自动在 _id 字段上建立索引。此外,您可以在一个或多个字段上创建索引。
使用Compass,我们可以非常轻松地建立索引。单击“索引”选项卡上的“创建索引”按钮,如下图所示 -
将出现一个对话框,如图所示。选择索引名称、要索引的字段、索引顺序(升序或降序)和其他选项。
使用 MongoEngine 时,通过在 Document 类定义的元字典中指定“indexes”键来创建索引。
Indexes 属性的值是字段列表。在下面的示例中,我们要求学生集合中的文档根据名称字段建立索引。
from mongoengine import *
con=connect('mydata')
class student(Document):
name=StringField(required=True)
course=StringField()
meta = {'indexes':['name']}
s1=student()
s1.name='Avinash'
s1.course='DataScience'
s1.save()
s2=student()
s2.name='Anita'
s2.course='WebDesign'
s2.save()
默认情况下,索引顺序为升序。可以通过在前面添加“+”(表示升序)或“-”(表示降序)来指定顺序。
要创建复合索引,请使用字段名称元组,可以选择附加 + 或 – 符号来指示排序顺序。
在下面的示例中,学生文档类包含名称和课程的复合索引的定义(注意 - 课程字段前面的符号,这意味着索引是按名称升序和按课程降序构建的。
from mongoengine import *
con=connect('mydata')
class student(Document):
name=StringField(required=True)
course=StringField()
meta = {'indexes':[('name','-course')]}
s1=student()
s1.name='Avinash'
s1.course='DataScience'
s1.save()
s2=student()
s2.name='Anita'
s2.course='WebDesign'
s2.save()
MongoDB Compass 将显示索引如下 -
“索引”的值可能是各种选项的字典,如下所示 -
| 领域 | 要索引的字段。 |
| CLS | 如果allow_inheritance打开,您可以配置索引是否应该自动添加_cls字段。 |
| 疏 | 索引是否应该稀疏。 |
| 独特的 | 索引是否应该是唯一的。 |
| 秒后过期 | 通过设置时间(以秒为单位)自动使集合中的数据过期 |
| 姓名 | 允许您指定索引的名称 |
| 整理 | 允许创建不区分大小写的索引 |
以下示例在名称字段上创建索引,该索引将在 3600 秒后过期。
from mongoengine import *
con=connect('mydata')
class student(Document):
name=StringField(required=True)
course=StringField()
meta = {'indexes':[{
'fields': ['name'],
'expireAfterSeconds': 3600
}
]
}
要指定文本索引,请在字段名称前添加“$”符号,对于散列索引,请使用“#”作为前缀。
当文档添加到集合中时,会自动创建如此指定的索引。要禁用自动创建,请在元属性中将“ auto_create_index ”设置为 False。
我们有Document 类的list_indexes()方法,用于显示可用索引的列表。
print (student.list_indexes())
[[('name', 1)], [('_id', 1)]]
要在元字典中没有的字段上创建索引,请使用create_index()方法。以下代码将在课程字段上创建索引 -
class student(Document):
name=StringField(required=True)
course=StringField()
meta = {'indexes':[{
'fields': ['name'],
'expireAfterSeconds': 3600
}
]}
student.create_index(['course'])
MongoEngine - 聚合
术语“聚合”用于处理数据并返回计算结果的操作。对集合中的一个或多个文档字段求和、计数和平均值可以称为聚合函数。
MongoEngine提供了aggregate()函数,封装了PyMongo的聚合框架。聚合操作使用集合作为输入并返回一个或多个文档作为结果。
MongoDB 使用数据处理管道的概念。一条管道可以有多个阶段。基本阶段提供了类似查询的过滤和操作。其他提供了按一个或多个字段进行分组和/或排序的工具、字符串连接任务、数组聚合工具等。
MongoDB 管道创建中定义了以下阶段 -
| 姓名 | 描述 |
|---|---|
| $项目 | 通过添加新字段或删除现有字段来重塑流中的每个文档。 |
| $匹配 | 过滤文档流以仅允许匹配的文档未经修改地传递到下一阶段。$match 使用标准 MongoDB 查询。 |
| $编辑 | 通过根据文档本身存储的信息限制每个文档的内容来重塑每个文档。 |
| $限额 | 限制不加修改地传递到管道的文档 |
| $跳过 | 跳过前 n 个文档,并将未修改的剩余文档传递到管道。 |
| $组 | 按给定标识符表达式对输入文档进行分组,并将累加器表达式应用于每个组。输出文档仅包含标识符字段和累积字段。 |
| $排序 | 按指定的排序键对文档流重新排序。 |
| $出 | 将聚合管道的结果文档写入集合。 |
聚合表达式使用字段路径来访问输入文档中的字段。要指定字段路径,请使用在字段名称前面加上美元符号 $$$ 前缀的字符串。表达式可以使用一个或多个布尔运算符($and、$or、$not)和比较运算符($eq、$gt、$lt、$gte、$lte 和 $ne)。
以下算术表达式也用于聚合 -
| $添加 | 添加数字以返回总和。接受任意数量的参数表达式 |
| $减去 | 返回第一个值减去第二个值的结果 |
| $乘 | 将数字相乘以返回乘积。接受任意数量的参数表达式 |
| $除法 | 返回第一个数字除以第二个数字的结果。接受两个参数表达式 |
| $mod | 返回第一个数字除以第二个数字的余数。接受两个参数表达式 |
以下字符串表达式也可以用于聚合 -
| $连接 | 连接任意数量的字符串 |
| $子字符串 | 返回字符串的子字符串,从指定索引位置开始直到指定长度 |
| 降低$ | 将字符串转换为小写。接受单个参数表达式 |
| $到上层 | 将字符串转换为大写。接受单个参数表达式 |
| $strcasecmp | 执行字符串比较,如果两个字符串相等则返回 0,如果第一个字符串大于第二个字符串则返回 1,如果第一个字符串小于第二个字符串则返回 -1 |
为了演示aggregate()函数在MongoEngine中的工作原理,我们首先定义一个名为orders的Document类。
from mongoengine import *
con=connect('mydata')
class orders(Document):
custID = StringField()
amount= IntField()
status = StringField()
然后我们在订单集合中添加以下文档 -
| _ID | 客户ID | 数量 | 地位 |
|---|---|---|---|
| 对象 ID("5eba52d975fa1e26d4ec01d0") | A123 | 500 | A |
| 对象 ID("5eba536775fa1e26d4ec01d1") | A123 | 250 | A |
| 对象 ID(“5eba53b575fa1e26d4ec01d2”) | B212 | 200 | D |
| 对象 ID("5eba540e75fa1e26d4ec01d3") | B212 | 400 | A |
仅当状态等于“A”时,aggregate() 函数才用于查找每个 custID 的金额字段总和。因此,管道构造如下。
管道的第一阶段使用 $match 来过滤 status='A' 的文档。第二阶段使用 $group 标识符对 CustID 上的文档进行分组并执行金额求和。
pipeline = [
{"$match" : {"status" : "A"}},
{"$group": {"_id": "$custID", "total": {"$sum": "$amount"}}}
]
该管道现在用作aggregate() 函数的参数。
docs = orders.objects().aggregate(pipeline)
我们可以使用 for 循环迭代文档光标。完整的代码如下 -
from mongoengine import *
con=connect('mydata')
class orders(Document):
custID = StringField()
amount= IntField()
status = StringField()
pipeline = [
{"$match" : {"status" : "A"}},
{"$group": {"_id": "$custID", "total": {"$sum": "$amount"}}}
]
docs = orders.objects().aggregate(pipeline)
for doc in docs:
print (x)
对于给定的数据,生成以下输出 -
{'_id': 'B212', 'total': 400}
{'_id': 'A123', 'total': 750}
MongoEngine - 高级查询
为了更高效地检索文档中的字段子集,请使用 Objects 属性的 only() 方法。这将显着提高性能,特别是对于长度极大的字段(例如 ListField)。将必填字段传递给 only() 函数。如果执行only()查询后访问其他字段,则返回默认值。
from mongoengine import *
con=connect('newdb')
class person (Document):
name=StringField(required=True)
city=StringField(default='Mumbai')
pin=IntField()
p1=person(name='Himanshu', city='Delhi', pin=110012).save()
doc=person.objects.only('name').first()
print ('name:',doc.name)
print ('city:', doc.city)
print ('PIN:', doc.pin)
输出
name: Himanshu city: Mumbai PIN: None
注意- 城市属性的值用作默认值。由于未指定 PIN 默认值,因此打印 None。
如果需要缺失字段,可以调用 reload() 函数。
当文档类具有 ListField 或 DictField 时,在迭代它时,任何 DBREf 对象都会自动取消引用。为了进一步提高效率,特别是在文档有ReferenceField的情况下,可以使用select_lated()函数来限制查询数量,该函数将QuerySet转换为列表并实现取消引用。
MongoEngine API 包含 Q 类,可用于构建由多个约束组成的高级查询。Q 表示查询的一部分,可以通过关键字参数语法和二进制 & 和 | 来初始化。运营商。
person.objects(Q(name__startswith=’H’) &Q(city=’Mumbai’))
MongoEngine - 文档继承
可以定义任何用户定义的 Document 类的继承类。如果需要,继承的类可以添加额外的字段。但是,由于此类不是 Document 类的直接子类,因此它不会创建新的集合,而是将其对象存储在其父类使用的集合中。在父类中,元属性' allow_inheritance下面的示例中,我们首先将employee定义为文档类并将allow_inheritance设置为true。工资等级源自employee,增加了两个字段dept和sal。Employee 对象以及工资类别存储在雇员集合中。
在下面的示例中,我们首先将employee定义为文档类并将allow_inheritance设置为true。工资等级源自employee,增加了两个字段dept和sal。Employee 对象以及工资类别存储在雇员集合中。
from mongoengine import *
con=connect('newdb')
class employee (Document):
name=StringField(required=True)
branch=StringField()
meta={'allow_inheritance':True}
class salary(employee):
dept=StringField()
sal=IntField()
e1=employee(name='Bharat', branch='Chennai').save()
s1=salary(name='Deep', branch='Hyderabad', dept='Accounts', sal=25000).save()
我们可以验证两个文档存储在员工集合中,如下所示 -
{
"_id":{"$oid":"5ebc34f44baa3752530b278a"},
"_cls":"employee",
"name":"Bharat",
"branch":"Chennai"
}
{
"_id":{"$oid":"5ebc34f44baa3752530b278b"},
"_cls":"employee.salary",
"name":"Deep",
"branch":"Hyderabad",
"dept":"Accounts",
"sal":{"$numberInt":"25000"}
}
请注意,为了识别相应的 Document 类,MongoEngine 添加了一个“_cls”字段并将其值设置为“employee”和“employee.salary”。
如果要向一组 Document 类提供额外的功能,但又不想产生继承开销,则可以首先创建一个抽象类,然后从该抽象类派生一个或多个类。要使类抽象,元属性“abstract”设置为 True。
from mongoengine import *
con=connect('newdb')
class shape (Document):
meta={'abstract':True}
def area(self):
pass
class rectangle(shape):
width=IntField()
height=IntField()
def area(self):
return self.width*self.height
r1=rectangle(width=20, height=30).save()
MongoEngine - Atomics更新
Atomics性是 ACID 事务属性之一。数据库事务必须是不可分割和不可简化的,以便它要么完全发生,要么根本不发生。这个属性称为Atomics性。MongoDB 仅支持单个文档的Atomics性,而不支持多文档事务。
MongoEngine 提供以下方法用于查询集的Atomics更新。
update_one() - 覆盖或添加与查询匹配的第一个文档。
update() - 对查询匹配的字段执行Atomics更新。
modify() - 更新文档并返回它。
这些方法可以使用以下修饰符。(这些修饰符位于字段之前,而不是之后)。
| 放 | 设置一个特定值 |
| 未设置 | 删除特定值 |
| 公司 | 将值增加给定量 |
| 十二月 | 将值减少给定量 |
| 推 | 将值附加到列表中 |
| 推送全部 | 将多个值附加到列表中 |
| 流行音乐 | 根据值删除列表的第一个或最后一个元素 |
| 拉 | 从列表中删除一个值 |
| 全部拉动 | 从列表中删除多个值 |
| 添加到集合 | 仅当列表中尚不存在时才将值添加到列表中 |
下面是一个Atomics更新的例子,我们首先创建一个名为tests的Document类,并在其中添加一个文档。
from mongoengine import *
con=connect('newdb')
class tests (Document):
name=StringField()
attempts=IntField()
scores=ListField(IntField())
t1=tests()
t1.name='XYZ'
t1.attempts=0
t1.scores=[]
t1.save()
让我们使用update_one()方法将名称字段从 XYZ 更新到 MongoDB。
tests.objects(name='XYZ').update_one(set__name='MongoDB')
Push 修饰符用于在 ListField(分数)中添加数据。
tests.objects(name='MongoDB').update_one(push__scores=50)
要将 attempts 字段加一,我们可以使用 inc 修饰符。
tests.objects(name='MongoDB').update_one(inc__attempts=1)
更新后的文档如下所示 -
{
"_id":{"$oid":"5ebcf8d353a48858e01ced04"},
"name":"MongoDB",
"attempts":{"$numberInt":"1"},
"scores":[{"$numberInt":"50"}]
}
MongoEngine-Javascript
MongoEngine 的 QuerySet 对象有exec_js()方法,允许在 MongoDB 服务器上执行 Javascript 函数。该函数处理以下参数 -
exec_js(code, *field_names, **options)
在哪里,
code - 包含要执行的 Javascript 代码的字符串
fields - 在你的函数中使用,它将作为参数传递
options - 您希望函数可用的选项(通过选项对象在 Javascript 中访问)
此外,还为函数的作用域提供了更多变量,如下所示 -
collection - 对应于 Document 类的集合的名称。这应该用于在 Javascript 代码中从数据库获取 Collection 对象。
query - QuerySet 对象生成的查询;传递到 Javascript 函数中 Collection 对象的 find() 方法。
options - 包含传递给 exec_js() 的关键字参数的对象。
请注意,MongoEngine 文档类中的属性可能在数据库中使用不同的名称(使用 Field 构造函数的 db_field 关键字参数进行设置)。