由 neevop 三月 2, 2023
连接数据库
# python use mongoengine -- pip3 install mongoengine
import mongoengine
mongoengine.connect(host="mongodb://172.16.34.82:27017/test")
# or connect with keywords
mongoengine.connect("test", host="172.16.34.82", port=27017)
# if should use auth
mongoengine.connect(host="mongodb://my_user:my_password@hostname:port/my_db?authSource=admin")
# or with keywords
mongoengine.connect('my_db', username='my_user', password='my_password', authentication_source='admin')
# provide a alias name when connect
mongoengine.connect(alias="db1", db="test")
# disconnect
mongoengine.disconnect()
# disconnect a particular connection
mongoengine,disconnect(alias="test")
// use mongosh -- apt install mongodb-mongosh
// connect to local server
mongosh "mongodb://localhost:27017"
mongosh --port 28015
// connect to remmote deployment
mongosh --host mongodb0.example.com --port 28015
mongosh "mongodb://mongodb0.example.com:28015"
//disconnect
exit
切换数据库
# python
import mongoengine
mongoengine.connect(db="sit", alias="sit", host="172.16.34.82", port=27017)
mongoengine.connect(db="test", alias="test", host="172.16.34.82", port=27017)
class SIT(mongoengine.Document):
name = mongoengine.StringField()
meta = {'db_alias': "sit"}
class TEST(mongoengine.Document):
name = mongoengine.StringField()
meta = {'db_alias': "test"}
from mongoengine import context_managers
# Make sure any aliases have been registered with register_connection() or connect()
# before using the context manager.
mongoengine.connect(db="result", alias="result", host="172.16.34.82", port=27017)
with context_managers.switch_db(TEST, "result") as TEST:
TEST(name='ROSS').save() # saves the "result"
// mongosh
// get all dbs
show dbs
// switch to sit db
use sit
定义集合
# python
from mongoengine import context_managers
# 指定集合
class Page(Document):
title = StringField(max_length=200, required=True)
meta = {'collection': 'cmsPage'}
# 切换集合
with context_managers.switch_collection(TEST, "result") as TEST:
TEST(name='ROSS').save() # saves the "result"
# 固定集合(Capped Collection)
class Log(Document):
ip_address = StringField()
meta = {'max_documents': 1000, 'max_size': 2000000}
定义文档
在 MongoDB 中,文档大致相当于关系型数据库中的一行。使用关系数据库时,行存储在表中,表具有行遵循的严格模式(schema)。MongoDB 将文档存储在集合中而不是表中——主要区别在于没有在数据库级别强制执行模式。好的schema通常需要试验和迭代。
MongoEngine 允许您为文档定义模式,因为这有助于减少编码错误,并允许在可能存在的字段上定义实用方法。
要为文档定义架构,请创建一个继承自 Document
. 通过将字段对象作为类属性添加到文档类来指定字段
import mongoengine as mg
import datetime
# 连接数据库,创建数据库别名
mg.connect(db="test", alias="test", host="172.16.34.82", port=27017)
# 定义文档模式,定义字段和所属数据库
class Page(mg.Document):
# 默认情况下,定义的字段不是必填,可以通过设置`required=True`将该字段设置为必填
title = mg.StringField(max_length=200, required=True)
# 字段也可以采用默认值,如果未提供值,将使用默认值
date = mg.DateTimeField(default=datetime.datetime.utcnow())
meta = {'db_alias': "test"}
# 实例化一个文档
page = Page(title="first documents")
# 指定插入的集合,插入文档
from mongoengine import context_managers
with context_managers.switch_collection(Page, "result"):
page.save()
结果如下:
test> db.result.find()
[
{
_id: ObjectId("63fdeb239f17ff42a578fda0"),
title: 'first documents',
date: ISODate("2023-02-28T11:51:46.763Z")
}
]
mongoengine中定义的字段类型有:
-
字典字段类型可以存储复杂的数据、其他字典、列表、对其他对象的引用,因此是最灵活的可用字段类型。
-
# 要创建嵌入式文档,只需像往常一样定义文档,但继承自 EmbeddedDocument 而不是 Document class Comment(EmbeddedDocument): content = StringField() # 使用 EmbeddedDocumentField 字段类型,提供嵌入文档类作为第一个参数 class Page(Document): comments = ListField(EmbeddedDocumentField(Comment)) # 实例化嵌入式文档字段 comment1 = Comment(content='Good work!') comment2 = Comment(content='Nice article!') page = Page(comments=[comment1, comment2])
-
# 另一种引用字段类型,类似(ReferenceField),允许引用任何类型的文档 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()
-
# 列表字段的第一个参数定义为该列表元素的字段类型 class Page(Document): tags = ListField(StringField(max_length=50))
-
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()
# 使用引用字段实现多对多关系(many to many) class User(Document): name = StringField() class Page(Document): content = StringField() authors = ListField(ReferenceField(User)) bob = User(name="Bob Jones").save() john = User(name="John Smith").save() Page(content="Test Page", authors=[bob, john]).save() Page(content="Another Page", authors=[john]).save() # Find all pages Bob authored Page.objects(authors__in=[bob]) # Find all pages that both Bob and John have authored Page.objects(authors__all=[bob, john]) # Remove Bob from the authors for a page. Page.objects(id='...').update_one(pull__authors=bob) # Add John to the authors for a page. Page.objects(id='...').update_one(push__authors=john)
# MongoDB默认不会检查数据完整性,所以删除引用数据后可能带来完整性问题。 # Mongoengine 的 ReferenceField 添加了一些功能来防止这些类型的数据库完整性问题,为每个引用提供删除规则规范 # 此示例中的声明意味着当删除 Employee 对象时,引用该员工的 ProfilePage 也将被删除。 class ProfilePage(Document): employee = ReferenceField('Employee', reverse_delete_rule=mongoengine.CASCADE) # 如下几个选项: # - mongoengine.DO_NOTHING : 默认设置,不会做任何事情。可能会导致数据引用悬空。 # - mongoengine.DENY : 如果该文档存在引用,拒绝删除。 # - mongoengine.NULLIFY : 引用该字段的字段将会被置为None(use mongoDB uset) # - mongoengine.CASCADE : 同时阐述包含该引用字段的文档 # - mongoengine.PULL : 从其他文档字段中删除该对象的引用(use mongoDB pull)
字段可以设置设置的选项有:
-
db_field
(Default: None)# 可以定义字段在MongoDB中的属性标签 class Page(Document): page_number = IntField(db_field="pageNumber")
-
required
(Default: False)定义字段是否必填
-
default
(Default: None)定义字段默认值
-
unique
(Default: False)定义该字段值是否需要保持唯一,否则会引发
NotUniqueError
-
unique_with
(Default: None)# 定义该字段在多个字段中保持唯一,可以是单个字段名称,也可以是字段名称的列表或元组 class User(Document): username = StringField(unique=True) first_name = StringField() last_name = StringField(unique_with='first_name')
-
primary_key
(Default: False)定义是否此字段用作集合的主键
-
choices
(Default: None)SIZE = ('S', 'M', 'L', 'XL', 'XXL') # 可迭代选项限定字段值范围 class Shirt(Document): size = StringField(max_length=3, choices=SIZE)
-
validation
(Optional)def _not_empty(val): if not val: raise ValidationError('value can not be empty') # 可以调用一个对象验证字段的值 class Person(Document): name = StringField(validation=_not_empty)
-
**kwargs
(Optional)
索引
指定索引可以提高查询速度。可以在文档模式的meta
属性中定义索引字段。也可以通过嵌入式字段定义复合索引。
class Page(Document):
category = IntField()
title = StringField()
rating = StringField()
created = DateTimeField()
meta = {
'indexes': [
# may either be a single field name, a tuple containing multiple field names, or a dictionary containing a full index definition.
'title', # single-field index
'$title', # text index
'#title', # hashed index
('title', '-rating'), # compound index
('category', '_cls'), # compound index
{
'fields': ['created'],
'expireAfterSeconds': 3600 # ttl index
}
]
}
2dsphere
索引是mongoDB推荐的索引,可以提供更好的查询性能。如下是
TTL
索引(Time To Live)是一种特殊的索引,可以决定文档失效的时间。
class Session(Document):
created = DateTimeField(default=datetime.utcnow)
meta = {
'indexes': [
{'fields': ['created'], 'expireAfterSeconds': 3600}
]
}
排序
可以在文档模式的meta
字段中定义文档的排序方式,预定义的排序可以通过调用order_by()
来覆盖。
class BlogPost(Document):
title = StringField()
published_date = DateTimeField()
meta = {
'ordering': ['-published_date']
}
文档继承
可以在文档模式的meta
字段中设置allow_inheritance
为True来允许类继承。
# Stored in a collection named 'page'
class Page(Document):
title = StringField(max_length=200, required=True)
meta = {'allow_inheritance': True}
# Also stored in the collection named 'page'
class DatedPage(Page):
date = DateTimeField()
Page(title='a funky title').save()
DatedPage(title='another title', date=datetime.utcnow()).save()
print(Page.objects().count()) # 2
print(DatedPage.objects().count()) # 1
文档抽象类
如果给文档模式类添加一些额外功能,不想子类继承这些功能,可以在meta
字段中指定抽象类。
class BaseDocument(Document):
meta = {
'abstract': True,
}
def check_permissions(self):
...
class User(BaseDocument):
...