NoSQL として有名な MongoDB を実際に触ってみたかったので、さっそく触ってみました。
MongoDB とはなにか?
簡単には、
- JSON 形式でデータ保持
- スキーマレス
- 検索がメチャメチャ早い
- スケールアウトしやすい
簡単すぎるかな。。笑
用語
NoSQL である MongoDB を扱う上で、最低限知っておくべき用語です。
- データベース: RDB と同じ意味のデータベース
- コレクション: RDB でいうところのテーブル。ドキュメントの集まり。
- ドキュメント: RDB でいうところのレコード。JSON 形式で情報が入っている。
- “_id”: RDB でいうところの “primary key”。一意の値が割り振られる。
環境
MongoDB は SaaS の mLab を使うので、ローカル環境に必要なのは Python だけです。
- Windows 7 SP1
- Python 3.6.5
- モジュール: PyMongo 3.6.1
mLab の準備
mLab (https://www.mlab.com/) とは、MongoDB のフルマネージドなホスティングサービスになります。
なぜ mLab を使うかというと、
- 単純にローカルに MongoDB をインストールしたくなかった
- データ量 500 MB まではフリーの利用枠がある
からです。こんな理由ですみません。笑
結果、接続でトラブりましたが、良い勉強になったと思います。
mLab の設定方法
まずは、mlab のアカウントを下記 URL から作成します。
無事アカウントが作成できると、下記のようなトップページにいきます。
右上の “MongoDB Deplayments” から “Create new” でデータベースを作成していきます。
AWS, GCP, Azure とメジャーなクラウドサービス上で、MongoDB をホストできます。
“Plan Type” は無料枠を使いたいので、”SANDBOX” を選択します。
その後、リージョンを選択します。
次に、データベース名を決めます。
ここでは “mongo_123” としました。このデータベース名は、後に Python からの接続で利用します。
最後に、内容の確認を行います。
こちらが、データベースを作成した直後の画面になります。
ただ、この状態ではまだ、外部からこのデータベースにアクセスできません。
アクセスできるようにするために、”Add database user” からユーザーを作成します。
- user: mongo_python
- password: mongo_python123
と設定しました。このユーザー名とパスワードは後に Python からの接続で利用します。
作成されたユーザー名は、リストとして確認することができます。
Python から MongoDB への CRUD
それでは、早速 Python から mLab 上の MongoDB を触っていきましょ!
接続
ここでかなりてこづりました。
mLab の画面から、
mongodb://>dbuser<:>dbpassword<@ds127841.mlab.com:27841/mongo_123
で接続できるような記述がありましたが、認証エラーで全然接続できませんでした。。。orz
Google で調べた結果、
db.authenticate(dbuser, dbpwd)
でどうにか接続できるようになりました。
問題の原因は不明ですが、お気をつけください!!
# mongo.py
from pymongo import MongoClient
# MongoDB Parameters
dbuser = 'mongo_python'
dbpwd = 'mongo_python123'
dbname = 'mongo_123'
# Establishing a Connection
# client = MongoClient('localhost', 27017) # default
# client = MongoClient('mongodb://localhost:27017/') # the same as above
client = MongoClient('ds127841.mlab.com', 27841)
# Accessing Databases
db = client[dbname]
db.authenticate(dbuser, dbpwd)
MongoClient( url/ip, port ) の第一引数、第二引数はアカウントごとに変わりますので、作成した mLab 上から確認しましょ。
Create: ドキュメントの作成
接続ができましたので、早速データを登録していきましょ!
ホリエモンの本を amazon.co.jp でスクレイピングしたいと思い、本の情報を登録することにしました。
# Inserting Single Document
book_data = {
'title': '10年後の仕事図鑑',
'content': 'AI、仮想通貨、モチベーション格差、46の仕事、働き方―。新たに始まる世界で、君はどう生きるか。',
'author' : ['堀江貴文', '落合陽一'],
'amazon_url': 'https://www.amazon.co.jp/1010年後の仕事図鑑-堀江-貴文/dp/4797394579'
}
collection = db.test_collection
collection.insert_one(book_data)
print('One book stored: {0}'.format(collection.inserted_id))
# Inserting Multiple Documents
book_1 = {
'title': '多動力',
'content': '堀江貴文のビジネス書の決定版!『多動力』',
'author' : '堀江貴文',
'amazon_url': 'https://www.amazon.co.jp/多動力-NewsPicks-Book-堀江貴文-ebook/dp/B072HVZ9RF/'
}
book_2 = {
'title': 'ゼロ なにもない自分に小さなイチを足していく',
'content': '堀江貴文はなぜ、逮捕され、すべてを失っても、希望を捨てないのか? ふたたび「ゼロ」となって、なにかを演じる必要もなくなった堀江氏がはじめて素直に、ありのままの心で語る、「働くこと」の意味と、そこから生まれる「希望」について。',
'author' : '堀江貴文',
'amazon_url': 'https://www.amazon.co.jp/ゼロ-なにもない自分に小さなイチを足していく-堀江-貴文-ebook/dp/B00G9KDQQU/'
}
book_3 = {
'title': '自分のことだけ考える。 無駄なものにふりまわされないメンタル術',
'content': '他人の目が気になる、人前に出ると緊張が止まらない、悪口を引きずってしまう、恥をかくのが怖い、モチベーションを持続できない…。こうした心の悩みを抱え、自分のやりたいことにブレーキをかけてしまっている人は多い。我慢せずに無駄なものを遠ざけ、心をフラットに生きる方法。メンタルコントロールの極意49。',
'author' : '堀江貴文',
'amazon_url': 'https://www.amazon.co.jp/146-自分のことだけ考える。-無駄なものにふりまわされないメンタル術-ポプラ新書/dp/B07C3MCR63'
}
new_result = collection.insert_many([book_1, book_2, book_3])
print('Multiple books stored: {0}'.format(new_result.inserted_ids))
登録されたドキュメントは、mLab 上からもの確認が可能です。
Unicode の変換が必要かなと思ったのですが、問題なく登録できているようです。
Read: ドキュメントの読み込み
登録したデータを呼び出してみましょ!
実際には HTML で表示させたりするのですが、それは次回に持ち越しということで。。
# Retrieving Single Document
tadou = collection.find_one({'title': '多動力'})
print('Sigle Document'.center(30, '='))
print(tadou['_id'])
# for searching by '_id', ObjectId needs to be created
from bson.objectid import ObjectId
print(collection.find_one({'_id': ObjectId(tadou['_id'])}))
# Retrieving Multipel Documents
horiemon_books = collection.find({'author': '堀江貴文'})
print('Multipel Documents'.center(30, '='))
for book in horiemon_books:
print(book['title'] + '\n' + book['amazon_url'])
ここで知っておきたいことは、“_id” で検索するには、オブジェクト作成しなければいけないということでしょうか。
知っておかないと結構ハマりそうなポイントですね。
Update: ドキュメントの更新
何かしらのももちろん想定できるので、その方法も確認しておきましょ!
# Updating Document
collection.find_one_and_update(
{'title': '多動力'}, {'$set': {'title': '多動力 (NewsPicks Book)'}})
print('Document Updated'.center(30, '='))
print(collection.find_one({'title': '多動力'})) # =>None
Delete: ドキュメントの削除
そして最後に、削除の方法を確認します。
# Deleting Document
collection.delete_one({'title': '10年後の仕事図鑑'})
print('Document Deleted'.center(30, '='))
print(collection.find_one({'title': '10年後の仕事図鑑'})) # =>None
まとめ
いかがでしたでしょうか?
大量のデータを入れたわけではないのでなんともの言えないですが、join を使わない分、なんとなく使いやすく思います。
得意・不得意なこともあるようなので、今後アプリを作りながら勉強していきたいですね!
フルのコードは こちらから 取得できます。