用Docker启动Mango
yaml 文件
# Use root/example as user/password credentials
version: '3.1'
services:
mongo:
image: mongo
restart: always
ports:
- 27017:27017
volumes:
- ./data:/data/db
- ./conf:/etc/mongo
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: passwd
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: passwd
ME_CONFIG_MONGODB_URL: mongodb://root:passwd@mongo:27017/
安装 MongoEngine
pip install mongoengine
数据类型
在MongoEngine中,你可以使用多种不同的字段类型来定义模型的属性,以适应不同的数据类型和需求。以下是一些常用的MongoEngine字段类型:
- StringField: 字符串类型,用于存储文本数据。
- IntField: 整数类型,用于存储整数数据。
- FloatField: 浮点数类型,用于存储浮点数数据。
- BooleanField: 布尔类型,用于存储True或False值。
- DateTimeField: 日期时间类型,用于存储日期和时间数据。
- ListField: 列表类型,用于存储多个值的列表。
- DictField: 字典类型,用于存储键值对的字典。
- EmbeddedDocumentField: 嵌套文档类型,用于嵌套存储其他文档。
- ReferenceField: 引用类型,用于存储对其他文档的引用。
- BinaryField: 二进制数据类型,用于存储二进制数据。
- DecimalField: 十进制数类型,用于存储精确的十进制数。
- URLField: URL类型,用于存储URL链接。
- EmailField: 邮件地址类型,用于存储电子邮件地址。
- GeoPointField: 地理坐标类型,用于存储地理位置坐标。
- UUIDField: UUID类型,用于存储通用唯一标识符。
- ComplexDateTimeField: 复杂日期时间类型,支持更复杂的日期时间表示。
这只是一些常见的MongoEngine字段类型,实际上还有更多类型和选项可供选择。根据你的数据需求,你可以选择适当的字段类型来定义模型的属性。详细的字段类型和选项可以在MongoEngine的官方文档中找到。
字段声明
在MongoEngine中,你可以使用各种字段参数来自定义字段的行为和特性。这些参数可以用于字段的定义,以调整字段在模型中的行为。以下是一些常用的字段参数:
- required: 指定字段是否是必需的,如果设置为True,插入文档时会检查该字段是否存在。
- default: 设置字段的默认值,在插入文档时如果未提供该字段的值,则会使用默认值。
- choices: 提供一个列表,限制字段的值只能从指定的选项中选择。
- unique: 指定字段的值是否必须在集合中是唯一的。
- min_value 和 max_value: 用于限制数值字段的最小值和最大值。
- min_length 和 max_length: 用于限制字符串字段的最小长度和最大长度。
- regex: 使用正则表达式来验证字段的值。
- sparse: 对于索引字段,设置为True表示在集合中仅包含具有该字段的文档。
- choices: 限制字段的值只能从指定的选项列表中选择。
- primary_key: 设置字段作为模型的主键,仅用于某些字段类型,如ObjectIdField。
- db_field: 自定义数据库中存储字段的名称。
- validation: 用于自定义验证逻辑的函数。
- verbose_name: 用于设置字段的可读性更好的名称。
- unique_with: 与unique一起使用,指定另一个字段来共同创建唯一约束。
- auto_created: 用于与信号(signals)一起工作,指定是否自动创建字段。
这只是一些常用的字段参数,实际上还有更多参数可以用来控制字段的行为。具体的参数取决于字段类型,你可以在MongoEngine的官方文档中找到关于每种字段类型及其参数的详细信息。
连接到数据库
# 连接到MongoDB数据库
connect(
db='App', # 数据库名称
host='10.1.1.25', # 数据库主机地址
port=27017, # 数据库端口号
username='root', # 可选:数据库用户名
password='passwd', # 可选:数据库密码
)
模型声明
from mongoengine import Document, StringField, IntField, connect, SequenceField
class User(Document):
"""
user_id # 自增
name # 用户名
passwd # 密码
address # 地址
phone # 电话号码
balance # 积分,默认为0
"""
user_id = SequenceField(primary_key=True) # 主键自增
name = StringField(required=True) # 不能为空
passwd = StringField(required=True)
address = StringField()
phone = StringField()
user_token = StringField()
balance = IntField(default=0) # 默认值0
引入字段(外键)
class User(Document):
name = StringField()
class Page(Document):
content = StringField()
author = ReferenceField(User)
john = User(name="John Smith")
john.save()
post = Page(content="Test Page")
post.author = john
post.save()
通用引用字段
还存在第二种参考字段。 ](https://docs.mongoengine.org/apireference.html#mongoengine.fields.GenericReferenceField)这允许您引用任何 kind of [
,因此不将``子类作为构造函数参数:
class Link(Document):
url = StringField()
class Post(Document):
title = StringField()
class Bookmark(Document):
bookmark_object = GenericReferenceField()
link = Link(url='http://hmarr.com/mongoengine/')
link.save()
post = Post(title='Using MongoEngine')
post.save()
Bookmark(bookmark_object=link).save()
Bookmark(bookmark_object=post).save()
创建数据和修改数据
# 创建对象并保存
user = User(name='Mek', passwd='123456', phone='10086')
user.save()
# 修改对象并保存
user.address = 'YiBin'
user.balance = 100
user.save()
# 删除单条数据
user.delete()
批量插入
class User(Document):
"""
user_id # 自增
name # 用户名
passwd # 密码
address # 地址
phone # 电话号码
balance # 积分,默认为0
"""
user_id = SequenceField(primary_key=True) # 主键自增
name = StringField(required=True) # 不能为空
passwd = StringField(required=True)
address = StringField()
phone = StringField()
user_token = StringField()
balance = IntField(default=0) # 默认值0
meta = {
'indexes': [
{'fields': ['name']}
]
}
def batch_(N: int = 10000):
# 创建一个空列表
data_list = []
for _ in range(N):
# 将对象声明为字典加入列表
data_list.append(
User(
name=Mm.get_random_letters(8),
passwd=Mm.get_random_letters(12),
phone=str(Mm.get_random_numbe(12)),
address=str(Mm.get_uuid4()),
balance=int(Mm.get_random_numbe(4))
)
)
# 使用insert() 批量插入
User.objects.insert(data_list)
删除数据
# 删除所有数据
all_user = User.objects()
all_user.delete()
查询数据
MongoEngine支持许多查询操作符,用于在查询中构建各种条件,以下是一些常见的查询操作符示例:
- 相等操作符:
__exact
: 精确匹配。=
: 等于,与__exact
等效。
- 模糊匹配操作符:
__iexact
: 不区分大小写的精确匹配。__contains
: 包含指定值。__icontains
: 包含指定值,不区分大小写。__startswith
: 以指定值开头。__istartswith
: 以指定值开头,不区分大小写。__endswith
: 以指定值结尾。__iendswith
: 以指定值结尾,不区分大小写。
- 比较操作符:
__gt
: 大于。__gte
: 大于等于。__lt
: 小于。__lte
: 小于等于。
- 数组操作符:
__contains
: 数组字段包含指定元素。__all
: 数组字段包含所有指定元素。__size
: 数组字段的大小等于指定值。
- 范围操作符:
__range
: 字段在指定范围内。__in
: 字段的值在指定值列表中。__nin
: 字段的值不在指定值列表中。
- 正则表达式操作符:
__regex
: 使用正则表达式进行匹配。__iregex
: 使用正则表达式进行匹配,不区分大小写。
这些只是一些常见的查询操作符示例,MongoEngine还支持更多操作符,可以根据实际需求在查询中使用。查询操作符的详细列表和用法可以在MongoEngine的官方文档中找到。
查询单条数据
# get() 函数
user = User.objects.get(name='VBZCFNOF')
print(user.name, user.phone, user.address)
# first() 函数
user = User.objects(name='VBZ2CFNOF').first()
# 区别是first()函数没有获取到数据时会返回None
比较查询
# __gt # 大于
# __gte # 大于等于
# __lt # 小于
# __lte # 小于等于
# __exact 或者 = # 等于
user_list = User.objects(balance__lte=1048)
for user in user_list:
print(user.name, user.balance)
文本匹配查询
# __icontains 包含且不区分大小写
user_list = User.objects(address__icontains='98')
for user in user_list:
print(user.name, user.balance, user.address)
# 按条件删除
user_list.delete()
多条件查询
# AND 查询
users = list(User.objects(name__contains="MEK", balance__gt=8000))
len(users)
for user in users:
print(user.name, user.balance)
# 更复杂的查询 与 或
# | 或表达
user_list = list(User.objects(Q(name__contains='MEB') | Q(name__contains='MED')))
for user in user_list:
print(user.name)
# & 与表达
user_list = list(User.objects(Q(name__contains='MEB') & Q(name__contains='A')))
for user in user_list:
print(user.name)
进阶操作
批量插入
# 创建一个空列表
data_list = []
# 将对象声明为字典加入列表
data_list.append(
User(
name=Mm.get_random_letters(8),
passwd=Mm.get_random_letters(12),
phone=str(Mm.get_random_numbe(12)),
address=str(Mm.get_uuid4()),
balance=int(Mm.get_random_numbe(4))
)
)
# 使用insert() 批量插入
User.objects.insert(data_list)
获取数据总条数
total_documents = User.objects.count()
print(total_documents)
查询时按字段排序
# 按balance 降序
user_list = User.objects(address__icontains='981a').order_by('-balance')
for user in user_list:
print(user.name, user.balance, user.address)
# 按balance 升序
user_list = User.objects(address__icontains='981a').order_by('balance')
for user in user_list:
print(user.name, user.balance, user.address)
获取指定行数
# 按balance 降序 获取前100条记录
first_100_users = User.objects[:100].order_by('-balance')
for user in first_100_users:
print(user.name, user.passwd, user.phone, user.balance)
分页
实现分页可以通过结合切片操作和计算来实现。你可以指定每页的记录数和当前页码,然后根据这些信息计算出起始位置和结束位置,再使用切片操作获取对应的记录。以下是一个简单的分页示例:
# 定义模型
class Product(Document):
name = StringField(required=True)
price = FloatField()
# 分页查询函数
def get_paginated_products(page_number, page_size):
start_index = (page_number - 1) * page_size
end_index = start_index + page_size
products = Product.objects.order_by('price')[start_index:end_index]
return products
# 分页参数
page_number = 2 # 第2页
page_size = 10 # 每页10条记录
# 获取分页结果
paginated_products = get_paginated_products(page_number, page_size)
# 打印分页结果
for product in paginated_products:
print(product.name, product.price)
索引
索引是数据库中用于加快数据检索速度的数据结构。在MongoDB中,索引是用于提高查询性能的重要机制。通过创建索引,可以让数据库更有效地定位和检索数据,从而减少查询操作的时间复杂度。
以下是一些关于MongoDB索引的详细信息:
- 索引类型:MongoDB支持多种类型的索引,包括单字段索引、复合索引、文本索引、地理空间索引等。不同类型的索引适用于不同的查询需求。
- 索引数据结构:MongoDB使用B树(B-tree)数据结构来实现索引。B树是一种自平衡的二叉树,它可以快速地进行插入、删除和查找操作。
- 单字段索引:最简单的索引类型,用于一个字段上的查询。你可以使用
create_index()
方法来在集合上创建单字段索引。 - 复合索引:索引多个字段的组合,可以优化涉及多个字段的查询。复合索引的字段顺序很重要,因为查询字段的顺序应该与索引的字段顺序一致。
- 唯一索引:保证索引字段的值在整个集合中是唯一的。可以通过设置
unique=True
来创建唯一索引。 - 文本索引:用于全文搜索,可以在文本字段上创建,支持文本搜索相关的查询操作。
- 地理空间索引:用于存储地理位置数据,例如经纬度。可以用来执行地理空间查询,如查找附近的点。
- 稀疏索引:创建索引时,只会为非空字段创建索引,可以节省存储空间。
- TTL索引:用于自动删除过期数据,可以设置索引字段的过期时间。
- 复合分片键索引:用于MongoDB分片集群中,用于划分数据到不同分片的依据。
在使用索引时需要注意以下几点:
- 索引会增加写入操作的开销,因为每次插入、更新或删除数据时都需要更新索引。
- 不适当的索引使用会导致查询性能下降,因此需要根据实际查询需求来选择创建索引。
- MongoDB中的查询优化器会根据查询计划自动选择最佳的索引,但仍然可以通过
hint()
方法来指定使用特定索引。 - 需要定期检查索引性能,删除不再使用的索引,以及考虑重建或重新组织索引以优化性能。
创建索引可以使用create_index()
方法,例如:
# 在"users"集合上创建"name"字段的单字段索引
db.users.create_index("name")
其他索引的创建方法
-
单字段索引:最简单的索引类型,用于单个字段上的查询。可以通过在字段的定义中使用
Index
类来创建单字段索引。from mongoengine import Document, StringField, Index class Person(Document): name = StringField(required=True) age = IntField() meta = { 'indexes': [ {'fields': ['name']} ] }
-
复合索引:索引多个字段的组合,用于优化涉及多个字段的查询。复合索引的字段顺序很重要,应该与查询中字段的顺序一致。
class Person(Document): name = StringField(required=True) age = IntField() meta = { 'indexes': [ {'fields': ['name', 'price']} ] }
-
文本索引:用于全文搜索,可以在文本字段上创建,支持文本相关的查询操作。
class Post(Document): title = StringField(required=True) content = StringField(required=True) meta = { 'indexes': [ {'fields': ['$title', '$content'], 'default_language': 'english'} ] }
-
地理空间索引:用于存储地理位置数据,例如经纬度。用于执行地理空间查询,如查找附近的点。
class Location(Document): name = StringField(required=True) coordinates = GeoPointField() meta = { 'indexes': [ Index([('coordinates', '2dsphere')]) ] }
-
TTL索引:用于自动删除过期数据,可以设置索引字段的过期时间(以秒为单位)。
class Session(Document): session_id = StringField(required=True) created_at = DateTimeField() meta = { 'indexes': [ Index([('created_at', 1)], expireAfterSeconds=3600) # 1小时后过期 ] }
6.唯一索引:我们为
Account
模型的username
字段创建了一个唯一索引。
from mongoengine import Document, StringField
class Account(Document):
username = StringField(unique=True, required=True)
meta = {
'indexes': [
{'fields': ['username'], 'unique': True}
]
}
这些是一些常见的索引类型,可以根据实际查询需求来选择适合的索引类型。