【问题标题】:How to check if a pymongo cursor has query results如何检查 pymongo 游标是否有查询结果
【发布时间】:2014-12-20 09:38:42
【问题描述】:

我需要检查 find 语句是否返回非空查询。

我正在做的事情如下:

query = collection.find({"string": field})
if not query: #do something

然后我意识到我的if 语句从未执行过,因为find 返回一个游标,查询是否为空。

因此我检查了documentation 并找到了两种可以帮助我的方法:

  1. count(with_limit_and_skip=False) 其中(来自描述):

    返回此查询的结果集中的文档数。

    这似乎是一个很好的检查方法,但这意味着我需要计算 游标中的所有结果都知道它是否为零,对吗?有点贵?

  2. retrieved 其中(来自描述):

    到目前为止检索到的文档数。

    我在一个空查询集上对其进行了测试,它返回零,但事实并非如此 明确它的作用,我不知道它是否适合我。

那么,这是检查find() 查询是否返回空集的最佳方法(最佳实践)?上述方法之一是否适合此目的?那么性能呢?还有其他方法吗?


要明确一点:我需要知道查询是否为空,并且我想找到光标在性能和 Pythonic 方面的最佳方式。

【问题讨论】:

  • 这取决于你想用它做什么
  • @VincentBeltman 我只需要知道查询是否使用该光标返回了某些内容。
  • 无论如何,您已经在您的 collection.find() 方法中执行查询。 “count”方法只是返回 find 方法返回给光标的文档数。您只需执行“如果 query.count > 0:”
  • @vintastic 我明白了,但性能如何? count 是否需要重新扫描所有找到的结果才能给我一个数字?
  • @boh 游标是指向查询结果集的指针。所以不需要重新扫描。

标签: python mongodb pymongo mongodb-query


【解决方案1】:

编辑虽然在 2014 年确实如此,但现代版本的 pymongo 和 MongoDB 已经改变了这种行为。买家当心:

.count() 是查找查询中返回的结果数的正确方法。 count() 方法不会耗尽游标的迭代器,因此您可以在迭代结果集中的项目之前安全地进行 .count() 检查。

在 MongoDB 2.4 中,count 方法的性能得到了极大的提升。唯一可能减慢您的count 的是查询是否设置了索引。要确定查询是否有索引,可以执行类似

query = collection.find({"string": field})
print query.explain()

如果您在结果中看到 BasicCursor,则您需要在您的 string 字段上为此查询建立索引。


编辑:正如@a​​lvapan 指出的,pymongo deprecated this pymongo 3.7+ 中的方法现在更喜欢您在单独的查询中使用count_documents

item_count = collection.count_documents({"string": field})

计算您在查询中返回的项目数的正确方法是在遍历查询后检查查询上的.retreived 计数器,或者首先检查enumerate查询:

# Using .retrieved
query = collection.find({"string": field})
for item in query:
    print(item)

print('Located {0:,} item(s)'.format(query.retrieved))

或者,另一种方式:

# Using the built-in enumerate
query = collection.find({"string": field})
for index, item in enumerate(query):
    print(item)

print('Located {0:,} item(s)'.format(index+1))

【讨论】:

  • 感谢您提出这个问题。 .count() 是检查非空查询的完美函数。我遇到了类似的问题,并通过此功能解决。
  • @VooDooNOFX,PyMongo 3.7 已弃用 cursor.count(),并要求我们改用 collection.count_documents()。那么我不知道新的 corrrect 方法会是什么来查找游标中返回的结果数。我们是否需要先collection.count_documents(query_string),检查号码,然后collection.find(query_string)才能得到真正的结果?但是新方式需要我们查询两次,而旧方式只查询一次,这似乎更好。
  • @AlvaPan 编辑了回复,谢谢。就个人而言,我更喜欢只执行查询,然后计算文档。没有多少可扩展的解决方案应该使用计数方法来提前知道他们正在查询多少文档,除了集合用例中的总文档计数。
【解决方案2】:

使用 find_one 而不是 find 怎么样?然后你可以检查你是否得到了结果或None。而如果“string”被索引了,你可以传递fields = {"string":1, "_id" :0},从而使它成为一个仅索引查询,这样更快。

【讨论】:

  • 字段string被索引了,但是我不能使用findOne,因为不能保证只有一个结果(实际上不太可能有一个)。
  • 据我了解,您只想知道您是否有任何查询结果,对吗?如果是这种情况, find_one 对于您的情况就足够了:如果它返回一个值,则意味着 find() 将找到至少一个结果,如果它返回 None,则意味着 find() 将返回 0 个结果.
  • 是的,但是如果没有结果,我会做一些事情,否则我会做一些有结果的事情,通常会显示所有结果。您是否说在索引字段上使用findOne 进行查询更有效,如果它不为空,请再次使用find 执行查询?
  • 另一种选择:只需迭代结果并做你的事。如果没有结果,它将是一个空循环,您可以使用代码中的标志来检测它(在循环内将标志设置为 True)。
  • 似乎 line find 比 find_one 快很多。见:blog.serverdensity.com/…
【解决方案3】:

根据我的测试,最快的方法是

if query.first():
    # do something

In [51]: %timeit query = MyMongoDoc.objects(); query.first()
100 loops, best of 3: 2.12 ms per loop

In [52]: %timeit query = MyMongoDoc.objects(); query.count()
100 loops, best of 3: 4.28 ms per loop

(使用 MongoDB 2.6.7,2015-03-26)

【讨论】:

    【解决方案4】:

    另一种解决方案是将光标转换为列表,如果光标没有任何数据,则为空列表,否则列表包含所有数据。

     doc_list = collection.find({}); #find all data
     have_list = True if len(list(doc_list)) else False;
    

    【讨论】:

    • 我也更喜欢这种方式,但这种方式的缺点是 list() 函数会完全耗尽光标。当您确定光标包含相对少量的文档时,最好使用它。
    • list 确实用尽了,考虑doc_list = list(collection.find({}));,其中没有结果返回一个空列表[],并在Python 中使用if not doc_list:len(doc_list)
    猜你喜欢
    • 2014-01-18
    • 2017-07-24
    • 2021-07-17
    • 2014-10-01
    • 1970-01-01
    • 2023-04-10
    • 2016-07-23
    • 2019-09-18
    • 1970-01-01
    相关资源
    最近更新 更多