Difference between MongoDB's find and findone calls
Based on my own benchmarks, find().limit(1)
is orders of magnitude faster than findOne()
.
There is either an error in the MongoDB documentation or a bug in findOne()
. findOne()
performs more like find().limit(N)
where N is the number of documents the query would return. I figured this out while trying to figure out why my simple queries were so slow!
update: response from a 10gen (MongoDB) engineer:
The two queries you are executing are very different. A find query returns a cursor, this is essentially a no-operation scenario, as no actual data is returned (only the cursor information). If you call findOne, then you are actually returning the data and closing the cursor. The docs should definitely be clearer :-)
Update: Indeed, if the find().limit(1)
document is retrieved, the orders of magnitude speed difference seems to disappear. Also, I could not reproduce the major speed difference with the MongoDB JavaScript driver. I originally benchmarked using the MongoDB Java driver.
findOne()
is indeed syntactic sugar for find().limit(1)
, given that you are actually retrieving the document (as opposed to just returning the cursor with find()
).
See Leftium's answer and updates for more detail.
The source code may helps a lot.
It's java but I guess it can help, too.
The findOne()
,
DBObject findOne(DBObject o, DBObject fields, DBObject orderBy, ReadPreference readPref,
long maxTime, TimeUnit maxTimeUnit) {
QueryOpBuilder queryOpBuilder = new QueryOpBuilder().addQuery(o).addOrderBy(orderBy)
.addMaxTimeMS(MILLISECONDS.convert(maxTime, maxTimeUnit));
if (getDB().getMongo().isMongosConnection()) {
queryOpBuilder.addReadPreference(readPref);
}
Iterator<DBObject> i = find(queryOpBuilder.get(), fields, 0, -1, 0, getOptions(), readPref, getDecoder());
DBObject obj = (i.hasNext() ? i.next() : null);
if ( obj != null && ( fields != null && fields.keySet().size() > 0 ) ){
obj.markAsPartialObject();
}
return obj;
}
And here is find()
public DBCursor find( DBObject ref ){
return new DBCursor( this, ref, null, getReadPreference());
}
As we can see that findOne()
calls find()
in it self, gets all the DBOject
in i
and then return the first.