python - 如何提高 pymongo 查询的性能

标签 python mongodb python-3.x pymongo pymongo-3.x

我继承了一个旧的 Mongo 数据库。让我们重点关注以下两个集合(为了提高可读性,删除了大部分内容):

收藏用户

db.user.find_one({"email": "user@host.com"})

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

集合条目(一个用户到多个条目):

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

正如您所看到的,两者之间没有 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)

运行 db.entry.find 大约需要 0.83 秒在我的笔记本电脑上查询,在 AWS 服务器(不是 MongoDB 服务器)上查询 0.54。

拥有大约 20000 个用户,需要花费 3 个小时才能获取所有数据。 这是您期望在 Mongo 中看到的延迟吗?我可以做些什么来改善这一点?请记住,MongoDB 对我来说相当陌生。

最佳答案

您可以使用 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 专家。

关于python - 如何提高 pymongo 查询的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39483692/

相关文章:

python - SQLAlchemy:为具有循环关系的模型类编写单元测试

python - 偶数和奇数之和包括超出范围的数字(如果不是偶数或奇数)

python - 检查环境变量是否存在的好习惯是什么?

python-3.x - 试图了解 python 作用域和全局关键字的行为

python - 如何使用 Python 发出 URL 请求并返回重定向到的 URL?

python - Python 哈希表中的元组与数组

python - Sphinx autodoc show-inheritance : How to skip undocumented, 中间基础?

javascript - 如何使用 JOI 验证请求正文中的对象数组

node.js - NodeJS 中具有 Promisified 函数的数据聚合

c# - 使用 C# 驱动程序是复制和复制 MongoDB 集合的更好方法吗?