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



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

我所做的是:

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

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

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

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

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

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

  2. retrieved(根据描述):

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

    我在一个空查询集上测试了它,它返回零,但它不是清楚它的作用,我不知道它是否适合我。

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


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

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

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

MongoDB 2.4大大提高了计数方法的性能。唯一可能降低count速度的是查询是否设置了索引。要了解查询中是否有索引,可以执行类似的操作

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

如果在结果中看到BasicCursor,则需要在string字段上为该查询创建索引。


EDIT:正如@alvapan所指出的,pymongo在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))

只使用find_one而不是find怎么样?然后你可以检查你是否得到了结果或None。如果对"string"进行了索引,则可以传递fields = {"string":1, "_id" :0},从而使其成为仅索引查询,这甚至更快。

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

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

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

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.72015-03-26)

我最终使用了简单的计数器,因为我不想无故调用服务器两次:

cursor = someCollection.find( query )
ct = 0
for doc in cursor:
    ct += 1
    # some code
if ct == 0:
    
    # cursor was empty

最新更新