2016-09-14 21 views
0

古いMongoデータベースを継承しました。(読みやすくするため、その内容のほとんどを削除)のは、以下の2つのコレクションに焦点を当ててみましょう:pymongoクエリのパフォーマンスを向上させる方法

コレクションユーザー

db.user.find_one({"email": "[email protected]"}) 

{'lastUpdate': datetime.datetime(2016, 9, 2, 11, 40, 13, 160000), 
'creationTime': datetime.datetime(2016, 6, 23, 7, 19, 10, 6000), 
'_id': ObjectId('576b8d6ee4b0a37270b742c7'), 
'email': '[email protected]' } 

コレクションエントリ(多くのエントリに1人のユーザー):

db.entry.find_one({"userId": _id}) 

{'date_entered': datetime.datetime(2015, 2, 7, 0, 0), 
'creationTime': datetime.datetime(2015, 2, 8, 14, 41, 50, 701000), 
'lastUpdate': datetime.datetime(2015, 2, 9, 3, 28, 2, 115000), 
'_id': ObjectId('54d775aee4b035e584287a42'), 
'userId': '576b8d6ee4b0a37270b742c7', 
'data': 'test'} 

ご覧のとおり、この2つの間にDBRefはありません。

私がしたいのは、エントリの総数と、指定された日付の後に更新されたエントリの数を数えることです。

これを行うには、私はPythonのpymongoライブラリを使用しました。以下のコードは私に必要なものを手に入れますが、それは痛いほど遅いです。

from pymongo import MongoClient 
client = MongoClient('mongodb://foobar/') 
db = client.userdata 

# First I need to fetch all user ids. Otherwise db cursor will time out after some time. 
user_ids = [] # build a list of tuples (email, id) 
for user in db.user.find(): 
    user_ids.append((user['email'], str(user['_id']))) 

date = datetime(2016, 1, 1) 
for user_id in user_ids: 
    email, _id = user_id 

    t0 = time.time() 

    query = {"userId": _id} 
    no_of_all_entries = db.entry.find(query).count() 

    query = {"userId": _id, "lastUpdate": {"$gte": date}} 
    no_of_entries_this_year = db.entry.find(query).count() 

    t1 = time.time() 
    print("delay ", round(t1 - t0, 2)) 

    print(email, no_of_all_entries, no_of_entries_this_year) 

これは、AWSのサーバー(ないのMongoDBサーバー)上で私のラップトップ上の両方db.entry.findクエリを実行するために周りに0.83秒かかり、そして0.54。

〜20000人のユーザーがいると、すべてのデータを取得するのに3時間かかります。 Mongoで見られるような待ち時間ですか?これを改善するために私は何ができますか? MongoDBは私にはかなり新しいことを覚えておいてください。

答えて

1

すべてのユーザーに対して2つの集計を個別に実行する代わりに、db.collection.aggregate()を持つすべてのユーザーに対して両方の集計を取得できます。

そして、(email, userId)タプルの代わりに、対応する電子メールを取得するのに使いやすいので、私たちはそれを辞書にします。

user_emails = {str(user['_id']): user['email'] for user in db.user.find()} 

date = datetime(2016, 1, 1) 
entry_counts = db.entry.aggregate([ 
    {"$group": { 
     "_id": "$userId", 
     "count": {"$sum": 1}, 
     "count_this_year": { 
      "$sum": { 
       "$cond": [{"$gte": ["$lastUpdate", date]}, 1, 0] 
      } 
     } 
    }} 
]) 

for entry in entry_counts: 
    print(user_emails.get(entry['_id']), 
      entry['count'], 
      entry['count_this_year']) 

結果にユーザーの電子メールアドレスを取得することはできますが、私はmongoの専門家でもありません。

+0

ありがとうございました。しかし、 'CommandCursor'オブジェクトには属性 'values'だけでなくlen(list(entry_counts))== 0もあります.MongoDBのバージョンはおそらく古すぎますか? –

+0

ああ。いいえ、それは単にタイプミスです。ごめんなさい。私はそれを修正します。 – Sevanteri

+0

これで修正されました。そして、うーん、entry_countsが空であるかどうかは分かりません。多分私のテストデータは少し違っていたかもしれません。 – Sevanteri

関連する問題