Symfoware

Symfowareについての考察blog

PyMongo 2.7.1のインストールと使い方(チュートリアル)

ずいぶん前にPyMongoをインストールして、MongoDBを操作してみました。
MongoDBをPythonで操作する(PyMongo使用)

久しぶりに触るので復習です。



PyMongoのインストール



Ubuntu 14.04にeasy_installでインストールしました。


$ sudo easy_install pymongo




インストールできたか、pythonコンソールを起動して、import pymongoを試してみます。


$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymongo
/usr/lib/python2.7/dist-packages/pkg_resources.py:1031: UserWarning: /home/baranche/.python-eggs is writable by group/others and vulnerable to attack when used with get_resource_filename. Consider a more secure location (set with .set_extraction_path or the PYTHON_EGG_CACHE environment variable).
warnings.warn(msg, UserWarning)
>>>




警告が表示されました。
気になるので調べてみると、

MONGODB WITH PYMONGO I - INSTALLATION


警告を取り去るのは難しいので、気になる場合はこのコマンドを実行しろとのこと。


$ chmod g-wx,o-wx ~/.python-eggs



これでとりあえず警告は表示されなくなりました。




チュートリアル



こちらのチュートリアルを参考に進めてきます。
http://api.mongodb.org/python/current/tutorial.html

接続するMongoDBは、以下でインストールした2.0.6です。
Debian 7にMongoDB 2.0.6 をapt-getでインストールする




MongoClientを使用したコネクション作成




ローカル接続の場合は、


  1. from pymongo import MongoClient
  2. client = MongoClient()



または、


  1. client = MongoClient('localhost', 27017)




今回、192.168.1.110で動いているMongoDBに接続したいので、以下のようにします。


  1. from pymongo import MongoClient
  2. client = MongoClient('192.168.1.110', 27017)




実行して、以下のエラーが発生する場合、bind_ipの設定に不備があると思います。


$ python sample.py
Traceback (most recent call last):
File "sample.py", line 6, in <module>
    client = MongoClient('192.168.1.110', 27017)
File "build/bdist.linux-x86_64/egg/pymongo/mongo_client.py", line 369, in __init__
pymongo.errors.ConnectionFailure: [Errno 111] Connection refused





サーバーの「/etc/mongodb.conf」を編集。
bind_ipを「0.0.0.0」とかに変更。


#bind_ip = 127.0.0.1
bind_ip = 0.0.0.0
#port = 27017




MongoDBを再起動して設定を反映させます。


# /etc/init.d/mongodb restart




これで接続できるようになるはずです。




データベース取得




データベースの取得は


  1. db = client.test_database



または


  1. db = client['test-database']



このようにして、MongoClientから取得します。
存在しないデータベース名を指定した場合は、自動的に作成されます。




コレクションの取得



コレクションの取得も、データベースの取得と同様


  1. collection = db.test_collection



または


  1. collection = db['test-collection']



このようにして取得します。
コレクションが存在しない場合は、自動的に作成されます。




保存するドキュメント



MongoDBに登録するドキュメントは、辞書型のオブジェクトを用意するだけでOK。
スキーマレスなデータベースは便利です。

例として、
auther : 文字列
text : 文字列
tags : リスト
date : 日付
というdictオブジェクトを登録することにします。


  1. import datetime
  2. post = {"author": "Symfo",
  3.         "text": u"SymfoBlogの登録内容です",
  4.         "tags": ["mongodb", "python", "pymongo", "symfoware"],
  5.         "date": datetime.datetime.utcnow()}







ドキュメントの登録




ドキュメントの登録は、コレクションに対してinsertを実行するだけです。
サンプルプログラムはこんな感じになります。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # 登録用のデータを準備
  11. post = {"author": "Symfo",
  12.         "text": u"SymfoBlogの登録内容です",
  13.         "tags": ["mongodb", "python", "pymongo", "symfoware"],
  14.         "date": datetime.datetime.utcnow()}
  15. # postsコレクションにドキュメントを登録
  16. post_id = posts.insert(post)
  17. # 登録したIDを表示
  18. print(post_id)





実行してみると、登録した時に自動で振られたIDが表示されました。


$ python sample.py
53d1079b04f0a22e57f70f8b







find_one()でドキュメントの取得



登録したpostデータを取得してみます。
コレクションから1つデータを取得するにはfind_one()を使います。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # 1つデータを取得して表示
  11. print(posts.find_one())




実行すると、ちゃんとデータが取得出来ました。
※適当な位置で改行しています。


$ python sample.py
{u'date': datetime.datetime(2014, 7, 24, 13, 18, 19, 973000),
u'text': u'SymfoBlog\u306e\u767b\u9332\u5185\u5bb9\u3067\u3059',
u'_id': ObjectId('53d1079b04f0a22e57f70f8b'),
u'author': u'Symfo',
u'tags': [u'mongodb', u'python', u'pymongo', u'symfoware']}







条件を指定して検索してみます。
authorがSymfoのデータを検索。


  1. posts.find_one({"author": "Symfo"})



これだと実行しても結果は変わりません。



  1. posts.find_one({"author": "MongoDB"})



として検索すると、結果がNoneになります。






ObjectIDを指定した検索



ドキュメントを登録すると、自動的に「_id」というキーが作成され、
ObjectIdが設定されます。

登録時「53d1079b04f0a22e57f70f8b」で登録されていることが
わかっているので、こんなプログラムで検索してみます。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # 1つデータを取得して表示(これはうまく行かないパターン)
  11. print(posts.find_one({"_id": "53d1079b04f0a22e57f70f8b"}))




実行結果は「None」になりました。


ObjectIdで検索したい場合、bson.objectidを使用します。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. from bson.objectid import ObjectId
  5. # MongoDBに接続
  6. client = MongoClient('192.168.1.110', 27017)
  7. # データベース(test_database)を取得
  8. db = client.test_database
  9. # postsコレクションを取得
  10. posts = db.posts
  11. # 1つデータを取得して表示
  12. print(posts.find_one({"_id": ObjectId("53d1079b04f0a22e57f70f8b")}))




これでデータが取得出来ました。





Bulk Inserts



複数のドキュメントを一括で登録するには、辞書型のオブジェクトをリストに詰めて
insertすればOKです。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # bulk insert用のリスト
  11. bulk_list = []
  12. # 1つめのドキュメント
  13. post = {"author": "Symfo",
  14.         "text": u"SymfoBlogの二個目の投稿です",
  15.         "tags": ["mongodb", "symfoware", "second"],
  16.         "date": datetime.datetime(2014, 10, 2)}
  17. bulk_list.append(post)
  18. # 2つめのドキュメント
  19. post = {"author": "NewAuthor",
  20.         "text": u"新しい筆者の投稿です",
  21.         "tags": ["mongodb", "new"],
  22.         "date": datetime.datetime(2014, 10, 3)}
  23. bulk_list.append(post)
  24. # postsコレクションにドキュメントを登録
  25. # ここでリストを引数に取る
  26. post_id = posts.insert(bulk_list)
  27. # 登録したIDを表示
  28. print(post_id)




実行すると、登録した2つのObjectIdが表示されます。


$ python sample.py
[ObjectId('53d10aa904f0a230e0afed93'), ObjectId('53d10aa904f0a230e0afed94')]







複数ドキュメントの表示



find_one()で1つのドキュメントが取得出来ました。
find()を使用すると、コレクションに登録されているドキュメントすべてが取得できます。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # postsコレクションのデータをすべて表示
  11. for post in posts.find():
  12.     print post





実行してみると、これまでに登録した3つのドキュメントが取得出来ました。


$ python sample.py
{u'_id': ObjectId('53d1079b04f0a22e57f70f8b'), u'author': u'Symfo', ...(略)}
{u'_id': ObjectId('53d10aa904f0a230e0afed93'), u'author': u'Symfo', ...(略)}
{u'_id': ObjectId('53d10aa904f0a230e0afed94'), u'author': u'NewAuthor', ...(略)}





autherが「Symfo」のデータを検索してみます。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # autherが「Symfo」のデータを検索
  11. for post in posts.find({"author": "Symfo"}):
  12.     print post




実行結果は以下の通り。


$ python sample.py
{u'_id': ObjectId('53d1079b04f0a22e57f70f8b'), u'author': u'Symfo', ...(略)}
{u'_id': ObjectId('53d10aa904f0a230e0afed93'), u'author': u'Symfo', ...(略)}







データ件数のカウント



コレクションに登録されているドキュメントの件数を求めるには、
コレクション.count()とすればOK。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. # コレクションに登録されているドキュメント数
  11. print posts.count()




3と表示されました。


$ python sample.py
3





条件を指定して件数をカウントする場合は、findと組み合わせます。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. from bson.objectid import ObjectId
  5. # MongoDBに接続
  6. client = MongoClient('192.168.1.110', 27017)
  7. # データベース(test_database)を取得
  8. db = client.test_database
  9. # postsコレクションを取得
  10. posts = db.posts
  11. # コレクションに登録されているautherがSymfoの件数
  12. print posts.find({'author':'Symfo'}).count()






範囲を指定した検索



範囲を指定してfindを実行してみます。

dateが2014/10/1以降のデータをauthorでソートして取得


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. d = datetime.datetime(2014, 10, 1)
  11. for post in posts.find({"date": {"$gt": d}}).sort("author"):
  12.     print post['text']





実行してみると、こんな結果が得られました。


$ python sample.py
新しい筆者の投稿です
SymfoBlogの二個目の投稿です







インデックス



よく検索に使用するフィールドはインデックスを設定しておくと、
効率よく検索が行えるようになります。

まず、通常の状態で使用しているカーソルとスキャンしているデータ数を表示してみます。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. # MongoDBに接続
  5. client = MongoClient('192.168.1.110', 27017)
  6. # データベース(test_database)を取得
  7. db = client.test_database
  8. # postsコレクションを取得
  9. posts = db.posts
  10. d = datetime.datetime(2014, 10, 1)
  11. print posts.find({"date": {"$gt": d}}).sort("author").explain()["cursor"]
  12. print posts.find({"date": {"$gt": d}}).sort("author").explain()["nscanned"]





BasicCursorを使用し、3件のデータをスキャンしています。


$ python sample.py
BasicCursor
3




インデックスを設定してみます。


  1. # -*- coding:utf-8 -*-
  2. import datetime
  3. from pymongo import MongoClient
  4. from pymongo import ASCENDING, DESCENDING
  5. # MongoDBに接続
  6. client = MongoClient('192.168.1.110', 27017)
  7. # データベース(test_database)を取得
  8. db = client.test_database
  9. # postsコレクションを取得
  10. posts = db.posts
  11. # インデックスを設定
  12. posts.create_index([("date", DESCENDING), ("author", ASCENDING)])
  13. d = datetime.datetime(2014, 10, 1)
  14. print posts.find({"date": {"$gt": d}}).sort("author").explain()["cursor"]
  15. print posts.find({"date": {"$gt": d}}).sort("author").explain()["nscanned"]




BtreeCursorが使用され、スキャンするデータ数が2になりました。


$ python sample.py
BtreeCursor date_-1_author_1
2

関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2014/07/24(木) 22:53:37|
  2. MongoDB
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<MongoDBのGUI管理ツール「Robomongo」をUbuntu 14.04にインストールする | ホーム | Debian 7にMongoDB 2.0.6 をapt-getでインストールする>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1431-c2d27f50
この記事にトラックバックする(FC2ブログユーザー)