如何检查pymongo游标是否有查询结果

52 投票
6 回答
50890 浏览
提问于 2025-04-29 11:35

我需要检查一个 find 语句是否返回了非空的查询结果。

我之前是这样做的:

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

然后我意识到我的 if 语句从来没有被执行,因为 find 返回的是一个游标,不管查询结果是空还是不空。

因此,我查看了 文档,发现有两个方法可以帮助我:

  1. count(with_limit_and_skip=False),根据描述:

    返回这个查询结果集中文档的数量。

    这似乎是检查的好方法,但这意味着我需要计算游标中的所有结果,以知道它是否为零,对吧?这样做有点耗费资源吧?

  2. retrieved,根据描述:

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

    我在一个空查询集上测试过,它返回零,但我不太清楚它具体是干什么的,也不知道这是否适合我。

那么,检查一个 find() 查询是否返回空结果集的最佳方法是什么呢?上面提到的方法中有哪个适合这个目的吗?性能方面怎么样?还有其他方法吗?


为了更清楚:我需要知道查询是否为空,并且我想找到在性能和符合 Python 风格方面的最佳方法。

暂无标签

6 个回答

0

我最后选择使用简单的计数器,因为我不想无缘无故地调用服务器两次:

cursor = someCollection.find( query )

ct = 0

for doc in cursor:

    ct += 1

    # some code

if ct == 0:
    
    # cursor was empty
4

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

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年3月26日)

13

另一种解决办法是把游标转换成列表。如果游标没有任何数据,那么就返回一个空列表;如果有数据,就返回一个包含所有数据的列表。

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

你可以试试用 find_one 来代替 find 吗?这样你就可以直接检查一下有没有结果,或者结果是 None(表示没有找到)。如果“string”这个字段是被索引的,你可以传入 fields = {"string":1, "_id" :0},这样就能让查询只用索引来查找,这样速度会更快哦。

47

编辑: 虽然在2014年这个说法是对的,但现代版本的pymongo和MongoDB已经改变了这个行为。购买时请注意:

.count() 是用来查找查询结果数量的正确方法。这个 count() 方法不会消耗你的游标(cursor)里的数据,所以你可以在遍历结果集之前安全地使用 .count() 来检查数量。

在MongoDB 2.4中,count 方法的性能得到了很大提升。唯一可能会让你的 count 变慢的因素是查询是否有索引。如果你想知道查询上是否有索引,可以执行类似下面的操作:

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

如果你在结果中看到 BasicCursor,那么你需要在这个查询的 string 字段上创建一个索引。


编辑: 正如 @alvapan 指出的那样,pymongo 在3.7+版本中弃用了这个 方法,现在建议你在单独的查询中使用 count_documents

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

正确计算查询返回的项目数量的方法是,在遍历查询后检查 .retrieved 计数器,或者一开始就使用 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))

撰写回答