使用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
キャプチャ.PNG

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))

如果您曾经使用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中,可以确认数据已经被插入。

キャプチャ.PNG

如果想在模型内部进一步定义结构,可以使用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()
キャプチャ.PNG

使用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)

答案

[<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)

结果

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()
キャプチャ.PNG

多个数据修改

キャプチャ.PNG

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
キャプチャ.PNG

删除数据

删除单个数据

class TestMongoEngine:
    def delete(self):
        rest = Company.objects.filter(name="普通のベンチャー").first().delete()
        return rest

if __name__ == "__main__":
        t = TestMongoEngine()
        rests = t.delete()
        print(rests)

执行完成后

キャプチャ.PNG

删除多个数据

我将删除两个具有知名度的创业公司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服务的文章。

bannerAds