LoginSignup
19
20

More than 5 years have passed since last update.

MongoEngineでMongoDBを触ってみる基礎編

Last updated at Posted at 2013-12-03

この記事は MongoDB Advent Calendar 2013 の三日目です。

MongoEngineってなんですか?

MongoEngineODM == Object Document Mapper というやつでMongoDB用のドキュメントをオブジェクト風に操作出来るようにするライブラリ。ドキュメントスキーマ定義、取得、保存を抽象化してくれます。

利用方法はDjangoのORMによく似ており、DjangoユーザであればMongoDB独特のクエリを学習しなくてもMongoDBを使用することが出来るでしょう。たぶん。

ただし、突っ込んだことをしようとするとMongoDBの知識が必要になります。

MongoEngineは何が出来て、何が出来ないのか

できること

  • ドキュメントスキーマの定義、制約の定義
  • ドキュメントの保存
  • ドキュメントの取得
  • カスタムクエリの発行

できないこと or めんどうくさいこと

  • バックアップ&リストアなどシステムレベルのコマンド実行
  • MongoDB固有のコマンド発行(出来なくも無いけど、とても面倒)

さわってみよう

インストール

pypiに登録されているのでpipでインストールします。

$ pip install mongoengine

接続先の設定

MongoDBへの接続はmongoengine.connectを使用します。 mongotest というデータベースに接続するには次のようにします。

from mongoengine import connect

connect('mongotest')

ホストやポートを指定する場合は引数を足してください。

connect('mongotest', host='192.168.0.10', port=999)

ドキュメントクラスを作る

mongoengine.document.Documentクラスを継承したサブクラスを定義します。各フィールドにはmongoengine.fields.*を割り当てます。フィールドクラスはIntFieldやStringFieldなど、pythonのオブジェクト名に似た名前で定義されています。

documents.py
from mongoengine.document import Document
from mongoengine import fields

class Athlete(Document):
    name = fields.StringField()
    age = fields.IntField()

    def __unicode__(self):
        return self.name

MongoDBはスキーマレスなのが良いところですが、個人的にはドキュメントクラス == スキーマを作って操作するほうが楽なように思います。余談ですが、1つのコレクションで複数のドキュメントクラスを操作することが出来るので、スキーマレスであるメリットはスポイルされません。

ドキュメントの追加

Athleteクラスをインスタンス化してsave()メソッドを呼び出します。

from documents import Athlete

# taro yamadaとhanako yamadaを追加する
athlete = Athlete(name=u"taro yamada", age=30)
athlete.save()
athlete = Athlete(name=u"hanako yamada", age=28)
athlete.save()

mongoコマンドで見てみると…

$ mongo mongotest
MongoDB shell version: 2.4.6
connecting to: mongotest

> show dbs
local   0.078125GB
mongotest   0.203125GB

データベースが自動的に作成されています。コレクションはというと、

> show collections
athlete
system.indexes

> db.athlete.find()
{ "_id" : ObjectId("529db366bdbf568299123013"), "name" : "taro yamada", "age" : 30 }
{ "_id" : ObjectId("529db458bdbf568299123014"), "name" : "hanako yamada", "age" : 28 }

というように、athleteコレクションにドキュメントが保存されています。

ドキュメントの取得

ドキュメント取得もAthleteクラスから操作を行います。objectsプロパティ経由でall()メソッドにより全件取得してみましょう(Djangoユーザにはおなじみですね)。

>>> Athlete.objects.all()
[<Athlete: taro yamada>, <Athlete: hanako yamada>]

取得条件を追加するにはfilter()メソッドを使います。

>>> Athlete.objects.filter(age=28)
[<Athlete: hanako yamada>]

ドキュメントを一つだけ取得する場合にはget()メソッドが使えます。

>>> Athlete.objects.get(age=28)
<Athlete: hanako yamada>

get()メソッド実行時にドキュメントが存在しないと例外が投げられます。

>>> Athlete.objects.get(name=u"inoki")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/key/.virtualenvs/mongoenginetest/lib/python2.7/site-packages/mongoengine/queryset/base.py", line 186, in get
    raise queryset._document.DoesNotExist(msg)
documents.DoesNotExist: Athlete matching query does not exist.

ドキュメント数を数えるためにcount()メソッドも使えます。

>>> Athlete.objects.all().count()
2

ドキュメントの更新

ドキュメントの更新は、インスタンスのsave()メソッドを実行します。ドキュメントがなければ追加されるし、あれば更新されるという具合ですね。

>>> athlete = Athlete.objects.get(name=u"taro yamada")
>>> athlete.age = 50
>>> athlete.save()
<Athlete: taro yamada>
>>> athlete.age
50

ドキュメントの削除

Athleteクラスのインスタンスに対してdelete()メソッドを発行します。

>>> hanako = Athlete.objects.get(age=28)
>>> hanako.delete()
>>> Athlete.objects.all()
[<Athlete: taro yamada>]

hanakoが削除されました:)

うっかりall()メソッドに続けてdelete()メソッドをチェインすると、全て消えてしまいます(filter()を使用した際も同様)。

>>> Athlete.objects.all().delete()
>>> Athlete.objects.all()
[]

taroも削除されています:)

19
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
20