使用Python中的MongoDB对象文档映射(ODM)进行操作
标题前的信息
这篇文章是Python入门MongoDB系列的续篇,但即使没有阅读前一篇文章,也可以理解其内容的结构。
如果对MongoDB感兴趣的话,希望你能一直陪伴到最后。
环境建设
MongoDB – 无结构化的数据库管理系统
在这篇文章中,我们将使用Docker进行环境搭建。
如果您想直接在本地安装MongoDB,请参考前一篇文章。
version: '3.1'
services:
mongo:
image: mongo
restart: always
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: example
我要启动容器。
docker-compose up -d mongo mongo-express

Python是一种高级编程语言。
Python使用mongoengine库。
pip install mongoengine
我将尝试进行连接。
我将尝试连接默认的本地数据库。
from mongoengine import connect
connect(db='local',
username="root",
password="example",
host='192.168.99.100',
port=27017,
authentication_mechanism='SCRAM-SHA-1',
authentication_source='admin'
)
如果执行没有出错,那就算成功了。关于其他的连接方法,请参考这里,让我们开始学习如何用Python操作MongoDB吧。
MongoDB的对象文档映射
ODM是指对象文档映射,字面上来说就是将对象映射到类似MongoDB的文档数据库中。
使用ODM的好处是可以约束数据的结构。
让我们来看一个实际的例子。
from mongoengine import connect, Document, EmbeddedDocument, \
StringField, IntField, DateTimeField, ListField, EmbeddedDocumentField
from datetime import datetime
connect(db='company',
username="root",
password="example",
host='192.168.99.100',
port=27017,
authentication_mechanism='SCRAM-SHA-1',
authentication_source='admin'
)
class Employee(EmbeddedDocument):
"""
社員詳細
"""
name = StringField(required=True)
age = IntField(required=False)
SCALE_CHOICES = (
("venture", "ベンチャー"),
("major", "大手")
)
class Company(Document):
"""
会社モデル
"""
name = StringField(required=True, max_length=32)
scale = StringField(required=True, choices=SCALE_CHOICES)
created_at = DateTimeField(default=datetime.now())
members = ListField(EmbeddedDocumentField(Employee))
from mongoengine import connect, Document, EmbeddedDocument, \
StringField, IntField, DateTimeField, ListField, EmbeddedDocumentField
from datetime import datetime
connect(db='company',
username="root",
password="example",
host='192.168.99.100',
port=27017,
authentication_mechanism='SCRAM-SHA-1',
authentication_source='admin'
)
class Employee(EmbeddedDocument):
"""
社員詳細
"""
name = StringField(required=True)
age = IntField(required=False)
SCALE_CHOICES = (
("venture", "ベンチャー"),
("major", "大手")
)
class Company(Document):
"""
会社モデル
"""
name = StringField(required=True, max_length=32)
scale = StringField(required=True, choices=SCALE_CHOICES)
created_at = DateTimeField(default=datetime.now())
members = ListField(EmbeddedDocumentField(Employee))
如果您曾经使用Django和SQLAlchemy来定义模型,那么您会对这个配置感到熟悉。
我们将使用实际定义的模型将数据存入MongoDB。
请将下面的代码附加到test.py中并执行。
您无需预先创建测试用的数据库。
class TestMongoEngine:
def add_one(self):
c_obj = Company(
name="有名ベンチャー",
scale="venture",
)
c_obj.save()
return c_obj
if __name__ == "__main__":
t = TestMongoEngine()
t.add_one()
从Mongo Express中,可以确认数据已经被插入。

如果想在模型内部进一步定义结构,可以使用EmbeddedDocumentField,因此将尝试使用它。
我们将修改之前追加到test.py的代码,并重新运行。
class TestMongoEngine:
def add_one(self):
member1 = Employee(
name="memberA",
age=40,
)
member2 = Employee(
name="memberB",
age=35,
)
c_obj = Company(
name="有名ベンチャーA",
scale="venture",
members=[member1, member2]
)
c_obj.save()
return c_obj
if __name__ == "__main__":
t = TestMongoEngine()
t.add_one()

使用ODM进行CRUD操作
由于上述的C(Create)例子已经作为第一个例子介绍了新的添加方法,所以现在我们将从数据加载开始继续介绍。
读取数据
单一加载
从先前新添加的数据库中读取一条数据。
...
class TestMongoEngine:
def get_one(self):
return Company.objects.first()
if __name__ == "__main__":
t = TestMongoEngine()
rest = t.get_one()
print(rest.id)
print(rest.name)
结果
5e7ed47419d1a75baa2bc3f3
有名ベンチャー
完全加载
...
class TestMongoEngine:
def get_more(self):
return Company.objects.all()
if __name__ == "__main__":
t = TestMongoEngine()
rest = t.get_more()
print(rest)
...
class TestMongoEngine:
def get_more(self):
return Company.objects.all()
if __name__ == "__main__":
t = TestMongoEngine()
rest = t.get_more()
print(rest)
答案
[<Company: Company object>, <Company: Company object>, <Company: Company object>]
通过id搜索进行读取
...
class TestMongoEngine:
def get_from_oid(self, oid):
return Company.objects.filter(pk=oid).first()
if __name__ == "__main__":
t = TestMongoEngine()
rest = t.get_from_oid("5e7ed47419d1a75baa2bc3f3")
print(rest.id)
print(rest.name)
...
class TestMongoEngine:
def get_from_oid(self, oid):
return Company.objects.filter(pk=oid).first()
if __name__ == "__main__":
t = TestMongoEngine()
rest = t.get_from_oid("5e7ed47419d1a75baa2bc3f3")
print(rest.id)
print(rest.name)
结果
5e7ed47419d1a75baa2bc3f3
有名ベンチャー
填補不足
如果想要在读取数据时对顺序进行排列,可以将元数据添加到公司模型中。
class Company(Document):
"""
会社モデル
"""
name = StringField(required=True, max_length=32)
scale = StringField(required=True, choices=SCALE_CHOICES)
created_at = DateTimeField(default=datetime.now())
members = ListField(EmbeddedDocumentField(Employee))
meta = {
'ordering': ['-created_at'] # metaを追記
}
文件
数据更新
仅需要一个选项:单一数据修正
...
class TestMongoEngine:
def update(self):
rest = Company.objects.filter(name="有名ベンチャー").update_one(name="普通のベンチャー")
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.update()
多个数据修改
class TestMongoEngine:
def update(self):
rest = Company.objects.filter(name="有名ベンチャーA").update(name="有名ベンチャーB")
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.update()
print(rests)
执行结果
2
删除数据
删除单个数据
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="普通のベンチャー").first().delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
执行完成后
删除多个数据
我将删除两个具有知名度的创业公司B的数据。
...
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="有名ベンチャーB").delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
执行结果
2
从Mongo Express中确认,CompanyDB中的所有数据都被删除了。
尾聲
若有时间,我打算写一篇关于使用Flask和MongoDB创建Web服务的文章。
...
class TestMongoEngine:
def update(self):
rest = Company.objects.filter(name="有名ベンチャー").update_one(name="普通のベンチャー")
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.update()

多个数据修改
class TestMongoEngine:
def update(self):
rest = Company.objects.filter(name="有名ベンチャーA").update(name="有名ベンチャーB")
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.update()
print(rests)
执行结果
2
删除数据
删除单个数据
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="普通のベンチャー").first().delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
执行完成后
删除多个数据
我将删除两个具有知名度的创业公司B的数据。
...
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="有名ベンチャーB").delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
执行结果
2
从Mongo Express中确认,CompanyDB中的所有数据都被删除了。
尾聲
若有时间,我打算写一篇关于使用Flask和MongoDB创建Web服务的文章。

class TestMongoEngine:
def update(self):
rest = Company.objects.filter(name="有名ベンチャーA").update(name="有名ベンチャーB")
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.update()
print(rests)
执行结果
2

删除数据
删除单个数据
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="普通のベンチャー").first().delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="普通のベンチャー").first().delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
执行完成后

删除多个数据
我将删除两个具有知名度的创业公司B的数据。
...
class TestMongoEngine:
def delete(self):
rest = Company.objects.filter(name="有名ベンチャーB").delete()
return rest
if __name__ == "__main__":
t = TestMongoEngine()
rests = t.delete()
print(rests)
执行结果
2
从Mongo Express中确认,CompanyDB中的所有数据都被删除了。
尾聲
若有时间,我打算写一篇关于使用Flask和MongoDB创建Web服务的文章。