'find() and findOne() methods in MongoDB showing different results

I have a Mongo database where in the users collection I have just 1 document. I do a find() and a findOne() operations using the username filter. I get what I think is an incorrect result from find() operation.

MongoDB shell version: 3.2.10
connecting to: test
Server has startup warnings: 
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] 
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] 
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2016-10-20T20:37:32.681-0700 I CONTROL  [initandlisten] 
> use lab2
switched to db lab2
> db.users.find()
{ "_id" : ObjectId("5807ac0765f24dd0660e4332"), "username" : "avtrulzz", "fname" : "Abc", "lname" : "Def", "email" : "[email protected]", "password" : "rootuser", "mobile" : NumberLong(1234567890) }
> db.users.findOne()
{
    "_id" : ObjectId("5807ac0765f24dd0660e4332"),
    "username" : "avtrulzz",
    "fname" : "Abc",
    "lname" : "Def",
    "email" : "[email protected]",
    "password" : "rootuser",
    "mobile" : NumberLong(1234567890)
}
> if (db.users.find({username : "noSuchUsername"})) {
... print ("Username exists"); 
... } else {
... print ("User does not exist"); }
Username exists
> if (db.users.findOne({username : "noSuchUsername"})) { print ("Username exists");  } else { print ("User does not exist"); }
User does not exist
> if (db.users.findOne({username : "avtrulzz"})) { print ("Username exists");  } else { print ("User does not exist"); }
Username exists

See the find() operation is returning user exists which is not true. findOne() is behaving correctly.enter image description here



Solution 1:[1]

First of all, basic difference between findOne() and find():

  • findOne() - if query matches, first document is returned, otherwise null.

  • find() - no matter the number of documents matched, a cursor is returned, never null.

So when put in an if condition, findOne() can convert to false when it doesn't match any document. As find() returns a cursor object and never returns null, will convert to true when put in an if condition.

find and findOne() return the following for empty collection :

enter image description here

Solution 2:[2]

The pitfall you find yourself in is the rather undocumented conversion from mongo shell objects to booleans in javascript:

findOne() returns a document, or nil/null/whatever-it-is-called

find() returns a cursor, which can be empty. But the object returned is always defined.

Solution 3:[3]

The the find() method returns a cursor which is always truthy even if the query criteria does not match any document.

On the other hand, the findOne returns the first document that matches your query criteria or null (JavaScript or the equivalent in your language driver) if there is not any document that matches the specified criteria.

> db.dropDatabase()
{ "dropped" : "test", "ok" : 1 }
> var cursor = db.collection.find();
> cursor;
> typeof cursor;
object
> !cursor;
false
> var document = db.collection.findOne();
> document;
null
> typeof document;
object
> !document;
true

Solution 4:[4]

The find() method will return an array, even if no documents match the search criteria. An empty array still exists, so it will act as truthy.

findOne() will either return exactly one document, or undefined. Undefined, by definition, is a falsy value.

When you know you will be searching for just one document, use findOne() to get a more accurate representation.

Solution 5:[5]

Maybe find is not correct candidate for boolean check, even if there is no data it returns an empty cursor which passes as true in boolean

if (db.users.find({username : "noSuchUsername"}).toArray().length>0) {
... print ("Username exists"); 
... } else {
... print ("User does not exist"); }

or

   if (db.users.find({username : "noSuchUsername"}).size()>0) {
    ... print ("Username exists"); 
    ... } else {
    ... print ("User does not exist"); }

findOne is working correctly because if no data is found it returns null which passes as false in boolean check.

Solution 6:[6]

use toArray() if you use find() method.

below 2 are the same :

myDoc.findOne()
myDoc.find().toArray()[0]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 frontendgirl
Solution 2 mtj
Solution 3 styvane
Solution 4 jlewis90
Solution 5
Solution 6 Siwei