最近pythonでmongodb使うなら

普通に使う場合

過去にそれなりに人気のあった(?)mongodb用のライブラリは軒並み廃れている感じがある。3.x系に追随できていない物が多い。pymongoを直接使ったほうがマシな印象。もし非同期を気にしたいならmotorなどは良いかもしれない。

あとまだ新しめで枯れていなそうだけれどumongoには頑張って欲しい。

テストについて

使えるならmongomockを使うと良い。databaseをmockしているので早い。ただしCIで回す時はmockではなくフルの環境でテストをしたほうが良い。

mongomockの使い方

mongomock自身のテストを見ると良い。概ねどうすれば良いか分かる。基本的にはclientの取得の部分を設定によって変えられるようにすると良い。

完全ではないけれど。ある程度のコードは動く。

import mongomock

# see also: https://github.com/mongomock/mongomock/blob/develop/tests/test__bulk_operations.py


def get_client():
    return mongomock.MongoClient()


def main():
    client = get_client()
    db = client["me"]

    db.people.drop()
    db.people.create_index("gender", unique=False, name="idx_gender", sparse=True, background=True)
    run(db)


def run(db):

    print("pre insert count: ", db.people.count())
    db.people.insert_one({"name": "foo", "age": 20, "gender": "F"})
    db.people.insert_one({"name": "bar", "age": 20, "gender": "F"})
    db.people.insert_one({"name": "boo", "age": 21, "gender": "M"})
    print("post insert count: ", db.people.count())

    print("query")
    for row in db.people.find({"gender": "F"}):
        print("\t", row)

    print("update")
    print(
        "\t",
        db.people.update_one({
            "gender": "F"
        }, {"$set": {
            "_updated": True
        },
            "$inc": {
                "age": 1
            }})
    )
    print(
        "\t",
        db.people.update_many({
            "gender": "F"
        }, {"$set": {
            "_updated": True
        },
            "$inc": {
                "age": 1
            }})
    )

    print("query")
    for row in db.people.find({"gender": "F"}):
        print("\t", row)

    print("pre bulk insert count: ", db.people.count())
    db.people.insert_many(
        [
            {
                "name": "X",
                "age": 0
            },
            {
                "name": "Y",
                "age": 0
            },
            {
                "name": "Z",
                "age": 0
            },
        ]
    )
    print("post bulk insert count: ", db.people.count())


if __name__ == "__main__":
    main()

実行結果。

pre insert count:  0
post insert count:  3
query
     {'age': 20, 'gender': 'F', 'name': 'foo', '_id': ObjectId('594fb52cc54d2d07c79297ac')}
     {'age': 20, 'gender': 'F', 'name': 'bar', '_id': ObjectId('594fb52cc54d2d07c79297ad')}
update
     <pymongo.results.UpdateResult object at 0x10ad29a68>
     <pymongo.results.UpdateResult object at 0x10ad29a68>
query
     {'age': 22, '_updated': True, 'gender': 'F', 'name': 'foo', '_id': ObjectId('594fb52cc54d2d07c79297ac')}
     {'age': 21, '_updated': True, 'gender': 'F', 'name': 'bar', '_id': ObjectId('594fb52cc54d2d07c79297ad')}
pre bulk insert count:  3
post bulk insert count:  6