読者です 読者をやめる 読者になる 読者になる

c-bata web

@c_bata_ のメモ。python多め

pymongo使い方まとめ(Python, MongoDB)

はじめに

MongoDBやpymongoについては以前基本的な事を勉強した(Python/FlaskからMongoDBを扱うpymongo勉強内容メモ - Programming Log)ので、Webアプリを開発する場合の事を意識して触ってみる。

DBスキーマ

最近、達成日と達成コメントを残せるTodoリストのような簡単なWebアプリを開発している。このWebアプリでは以下の様な形式でMongoDBに保存しようと考えている。

{
    'TwitterID':u'__masapy__',
    'TaskNum':3,
    'Tasks':[
        {
            'TaskId':0,
            'TaskTitle':u'Fishing',
            'TaskDone':False,
        },
        {
            'TaskId':1,
            'TaskTitle':u'Cycling',
            'TaskDone':True,
            'DoneComment':u'たのしかった!',
            'DoneDate':u'2014-05-18'
        },
        {
            'TaskId':2,
            'TaskTitle':u'Programming',
            'TaskDone':False,
        }
    ]
}

...他のユーザ

準備

>>> from pymongo import MongoClient
>>> client = MongoClient()
>>> db = client['UserDB'] # データベースを取得
>>> col = db.User  # Userコレクションを取得

pymongoの重要なメソッド

  • find() : 全部
  • find({'key':'value'}) : 条件にマッチするのを全部取得
  • find_one({'key':'value'}) : 条件にマッチするのを1つとってくる
  • count() : findで取得したオブジェクトの数をカウントする

POST

ユーザ登録

>>> col.insert({'TwitterId':'__masapy__','TaskNum':0,'Tasks':[]})

タスク登録

>>> task_add = col.find_one({'TwitterId':'__masapy__'})
>>> task_num = task_add['TaskNum']
>>> task_add['Tasks'].append({'TaskId':task_num,'TaskTitle':u'Programming'},'TaskDone':False)
>>> task_add['TaskNum'] += 1
>>> col.save(task_add) # DBに反映

GET

ユーザ一覧

>>> for user in col.find():
        print user['TwitterId']

あるユーザのタスク一覧

>>> for task in col.find_one({'TwitterId':'__masapy__'})['Tasks']:
        print task['TaskId'], task['TaskTitle'], task['TaskDone']

実際の処理ではオブジェクトごとJinja2テンプレートに渡して、そちらでループすればいいので、

return render_template('tasks.html',
            tasks = col.find_one({'TwitterId':'__masapy__'})['Tasks'])

みたいな感じになると思う.

PUT

  • 達成処理(TaskDoneをTrue,DoneCommentとDoneDateを追加)
>>> task_id = (POSTされたURIから更新したいtaskのTaskIdを決定)
>>> done_comment = (達成コメント)
>>> done_date = (達成日:Datetimeオブジェクト)
>>>
>>> user = col.find_one({'TwitterId':'__masapy__'}):
>>> for task in user['Tasks']:
>>>    if task['TaskId'] == task_id:
>>>        task['TaskDone'] = True
>>>        task['DoneComment'] = done_comment
>>>        task['DoneDate'] = done_date
>>>        col.save(user)

ちゃんと動くか確かめてみた↓

In [2]: User = {
   ...:         'TwitterID':u'__masapy__',
   ...:         'TaskNum':3,
   ...:         'Tasks':[
   ...:                 {
   ...:                         'TaskId':0,
   ...:                         'TaskTitle':u'Fishing',
   ...:                         'TaskDone':False,
   ...:                 },
   ...:                 {
   ...:                         'TaskId':1,
   ...:                         'TaskTitle':u'Cycling',
   ...:                         'TaskDone':True,
   ...:                         'DoneComment':u'たのしかった!',
   ...:                         'DoneDate':u'2014-05-18'
   ...:                 },
   ...:                 {
   ...:                         'TaskId':2,
   ...:                         'TaskTitle':u'Programming',
   ...:                         'TaskDone':False,
   ...:                 }
   ...:         ]
   ...: }

In [3]: print User['TwitterID']
__masapy__

In [4]: for task in User['Tasks']:
   ...:     if task['TaskId'] == 2:
   ...:         task['TaskDone'] = True
   ...:         task['DoneComment'] = u'たのしかった'
   ...:         task['DoneDate'] = '2012-05-18'
   ...:     else:
   ...:

In [5]: print User
{
    'Tasks': [
        {'TaskTitle': u'Fishing', 'TaskDone': False, 'TaskId': 0},
        {'DoneDate': u'2014-05-18', 'TaskTitle': u'Cycling', 'TaskDone': True, 'DoneComment': u'\u305f\u306e\u3057\u304b\u3063\u305f\uff01', 'TaskId': 1},
        {'DoneDate': '2012-05-18', 'TaskTitle': u'Programming', 'TaskDone': True, 'DoneComment': u'\u305f\u306e\u3057\u304b\u3063\u305f', 'TaskId': 2}
    ],
    'TaskNum': 3,
    'TwitterID': u'__masapy__'
}

いいかんじ!

DELETE

アカウント削除

>>> col.remove({'TwitterId':'__masapy__'})

で可能だとは思うけど、念のためオブジェクトID指定した方がいいのかも?

>>> account_id = col.find_one({'TwitterId':'__masapy__'})['_id']
>>> col.remove({'u_id':account_id})

タスク削除

>>> task_id = (POSTされたURIから削除したいtaskのTaskIdを決定)
>>> user = col.find_one({'TwitterId':'__masapy__'}):
>>> for task in user['Tasks']:
>>>    if task['TaskId'] == task_id:
>>>        user['Tasks'].remove(tasks)
>>>        col.save(user)
>>>        break
>>>    else:
>>>        print u"そのようなタスクはありません"

参考資料