2016-09-14 4 views
0

Ich habe eine alte Mongo-Datenbank geerbt. Lassen Sie uns auf den folgenden zwei Sammlungen konzentrieren (die meisten ihrer Inhalte zur besseren Lesbarkeit entfernt):So verbessern Sie die Leistung von Pymongo-Abfragen

Sammlung Benutzer

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]' } 

Sammlungen Eintrag (ein Benutzer zu viele Einträge):

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'} 

Wie Sie sehen können, gibt es keinen DBRef zwischen den beiden.

Was ich tun möchte, ist die Gesamtzahl der Einträge zu zählen, und die Anzahl der Einträge nach einem bestimmten Datum aktualisiert.

Um dies zu tun, habe ich Python Pymongo-Bibliothek verwendet. Der Code unten bringt mir, was ich brauche, aber es ist schmerzhaft langsam.

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) 

Es dauert etwa 0,83 Sekunden beiden db.entry.find Abfragen auf meinem Laptop zu laufen, und 0,54 auf einem AWS-Server (nicht der MongoDB-Server).

Mit ~ 20000 Benutzern dauert es schmerzhafte 3 Stunden, um alle Daten zu erhalten. Ist das die Art von Latenz, die Sie in Mongo erwarten würden? Was kann ich tun, um dies zu verbessern? Bedenken Sie, dass MongoDB für mich ziemlich neu ist.

Antwort

1

Anstatt zwei Aggregate für alle Benutzer separat auszuführen, können Sie einfach beide Aggregate für alle Benutzer mit db.collection.aggregate() abrufen.

Und anstelle von (email, userId) Tupeln machen wir es zu einem Wörterbuch, da es einfacher ist, die entsprechende E-Mail zu erhalten.

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']) 

Ich bin mir ziemlich sicher, dass der E-Mail-Adresse in das Ergebnis des Benutzers immer getan werden könnte, aber ich bin kein Experte Mongo entweder.

+0

Danke. Allerdings hat nicht nur das 'CommandCursor'-Objekt kein Attribut' values ​​', sondern auch len (list (entry_counts)) == 0. Vielleicht ist die MongoDB-Version, die ich habe, zu alt? –

+0

Oh verdammt. Nein, das ist nur ein Tippfehler. Es tut uns leid. Ich werde das reparieren. – Sevanteri

+0

Es ist jetzt behoben. Und hmmm, nicht sicher, ob die entry_counts leer sind. Vielleicht waren meine Testdaten ein bisschen anders. – Sevanteri

Verwandte Themen