PythonでMongoDBを操作してみる

Python

ドライバインストール

pipenv --python 3
pipenv shell
pipenv install pymongo
pipenv install pymongo[srv]

以下のコードで接続できることを確認します。

from pymongo import MongoClient
from pprint import pprint

MONGODB_URL = ''
client = MongoClient(MONGODB_URL)
db = client.admin

serverStatusResult = db.command("serverStatus")
pprint(serverStatusResult)

CRUD

データ作成

businessというデータベースにreviewsというコレクション(RDBでいうテーブル)を作成してデータを登録するサンプルです。CREATE DATABASEなどを書くことなく登録ができるのは簡単ですが、初見では戸惑いました。慣れるしかないですね。

from pymongo import MongoClient
from random import randint

MONGODB_URL = "YOUR MONGODB URL"
client = MongoClient(MONGODB_URL)
db = client.business

names = ['Kitchen','Animal','State', 'Tastey', 'Big','City','Fish', 'Pizza','Goat', 'Salty','Sandwich','Lazy', 'Fun']
company_type = ['LLC','Inc','Company','Corporation']
company_cuisine = ['Pizza', 'Bar Food', 'Fast Food', 'Italian', 'Mexican', 'American', 'Sushi Bar', 'Vegetarian']

# businesses = []
for x in range(1, 501):
    business = {
        'name' : names[randint(0, (len(names) - 1))] + ' ' + names[randint(0, (len(names) - 1))] + ' ' + company_type[randint(0, (len(company_type) - 1))],
        'rating' : randint(1, 5),
        'cuisine': company_cuisine[randint(0, (len(company_cuisine) - 1))]
    }
    # businesses.append(business)

    result = db.reviews.insert_one(business)
    print('Created {0} of 500 as {1}'.format(x, result.inserted_id))

# db.reviews.insert_many(businesses)
print('finished creating 500 business reviews')

21行目で1つずつreviewsに登録していますが、一括で登録したい場合は12,19,24行目のコメントアウトしている箇所を参考に実装すれば可能です。insert_manyの戻り値はIDのリストです。

データ取得

1件、count関数、集約関数をそれぞれ使用する例です。

from pymongo import MongoClient

MONGODB_URL = "YOUR MONGODB URL"
client = MongoClient(MONGODB_URL)
db = client.business

fivestar = db.reviews.find_one({'rating': 5})
print(fivestar)

print('The number of 5 star reviews:')
fivestarcount = db.reviews.count_documents({'rating': 5})
# fivestarcount = db.reviews.find({'rating': 5}).count_documents()
print(fivestarcount)

print('\nThe sum of each rating occurance across all data grouped by rating ')
stargroup = db.reviews.aggregate(
    [
        {
            '$group':
            {'_id': '$rating',
            "count": {
                '$sum': 1
                }
            }
        },
        {
            '$sort': {
                '_id': 1
            }
        }
    ]
)

for group in stargroup:
    print(group)

集約関数の詳しい説明は https://docs.mongodb.com/manual/aggregation/ を参照してください。

12行目の書き方だと以下のよう非推奨と警告が出るので、11行目のcount_documents()を使うようにしました。

DeprecationWarning: count is deprecated. Use Collection.count_documents instead.

データ更新

いいね機能を追加した場合、いいねの数を保存する列が必要になります。MongoDBの場合はALTER TABLEを使うことなく変更することが可能です。

from pymongo import MongoClient
from pprint import pprint

MONGODB_URL = "YOUR MONGODB URL"
client = MongoClient(MONGODB_URL)
db = client.business

ASingleReview = db.reviews.find_one({})
print('A sample document:')
pprint(ASingleReview)

result = db.reviews.update_one({'_id': ASingleReview.get('_id')}, {'$inc': {'likes': 1}})
print('Number of documents modified: ' + str(result.modified_count))

UpdatedDocument = db.reviews.find_one({'_id': ASingleReview.get('_id')})
print('The updated document:')
pprint(UpdatedDocument)

データ削除

1件、複数削除の例です。データ更新と書き方が似ていますね。

from pymongo import MongoClient
from pprint import pprint

MONGODB_URL = "YOUR MONGODB URL"
client = MongoClient(MONGODB_URL)
db = client.business

ASingleReview = db.reviews.find_one({})
print('A sample document:')
pprint(ASingleReview)

single_delete_result = db.reviews.delete_one({'_id': ASingleReview.get('_id')})
print('Number of documents deleted: ' + str(single_delete_result.deleted_count))

many_delete_result = db.restaurants.delete_many({'category': 'Bar Food'})
print('Number of documents deleted: ' + str(many_delete_result.deleted_count))

トラブルシューティング

user is not allowed to do action ...

ユーザーの権限がないと怒られているようです。

(getting-started-with-python-and-mongodb-gdumt-jF) C:\Users\polar\workspace\getting-started-with-python-and-mongodb>python mongodbtest.py
Traceback (most recent call last):
  File "C:\Users\polar\workspace\getting-started-with-python-and-mongodb\mongodbtest.py", line 8, in <module>
    serverStatusResult = db.command("serverStatus")
  File "C:\Users\polar\.virtualenvs\getting-started-with-python-and-mongodb-gdumt-jF\lib\site-packages\pymongo\database.py", line 753, in command
    return self._command(sock_info, command, secondary_ok, value,
  File "C:\Users\polar\.virtualenvs\getting-started-with-python-and-mongodb-gdumt-jF\lib\site-packages\pymongo\database.py", line 635, in _command
    return sock_info.command(
  File "C:\Users\polar\.virtualenvs\getting-started-with-python-and-mongodb-gdumt-jF\lib\site-packages\pymongo\pool.py", line 710, in command
    return command(self, dbname, spec, secondary_ok,
  File "C:\Users\polar\.virtualenvs\getting-started-with-python-and-mongodb-gdumt-jF\lib\site-packages\pymongo\network.py", line 158, in command
    helpers._check_command_response(
  File "C:\Users\polar\.virtualenvs\getting-started-with-python-and-mongodb-gdumt-jF\lib\site-packages\pymongo\helpers.py", line 167, in _check_command_response
    raise OperationFailure(errmsg, code, response, max_wire_version)
pymongo.errors.OperationFailure: user is not allowed to do action [serverStatus] on [admin.], full error: {'ok': 0, 'errmsg': 'user is not allowed to do action [serverStatus] on [admin.]', 'code': 8000, 'codeName': 'AtlasError'}

接続を試みたユーザーの「Database User Privileges」を「Atlas admin」に変更するとうまくいきました。

参考

Getting Started with Python and MongoDB