Вопрос:
У меня есть база данных Mongo, где в коллекции пользователей есть только 1 документ. Я делаю операции find() и findOne() с использованием фильтра имени пользователя. Я получаю неправильный результат операции find().
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» : «test@yahoo.co.in», «password» : «rootuser», «mobile» : NumberLong(1234567890) } > db.users.findOne() { «_id» : ObjectId(«5807ac0765f24dd0660e4332»), «username» : «avtrulzz», «fname» : «Abc», «lname» : «Def», «email» : «test@yahoo.co.in», «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
Смотрите, операция find() возвращает пользователя, который существует, что не соответствует действительности. findOne() ведет себя правильно.
Лучший ответ:
Прежде всего, принципиальная разница между findOne() и find():
-
findOne() – если запрос совпадает, возвращается первый документ, в противном случае – ноль.
-
find() – число документов соответствует, курсор возвращается, никогда не ноль.
Поэтому, если поместить в условие if, findOne() может преобразовать в false, если оно не соответствует ни одному документу. Так как find возвращает объект курсора и никогда не возвращает null, он будет преобразован в true, если он помещен в условие if.
find и findOne() возвращают следующее для пустой коллекции:
Ответ №1
Ловушка, в которую вы попадаете, – это довольно недокументированное преобразование из объектов оболочки mongo в boolean в javascript:
findOne() возвращает документ, или nil/null/whatever-it-is-called
find() возвращает курсор, который может быть пустым. Но возвращаемый объект всегда определяется.
Ответ №2
Метод find() возвращает cursor, который всегда truthy, даже если критерии запроса не соответствуют какому-либо документу.
С другой стороны, findOne возвращает первый документ, соответствующий вашим критериям запроса, или null (JavaScript или эквивалент в драйвере вашего языка), если нет документа, соответствующего указанным критериям.
> 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 Ответ №3
Возможно, поиск не является правильным кандидатом для логической проверки, даже если нет данных, он возвращает пустой курсор, который проходит как истинный в булевом
if (db.users.find({username : «noSuchUsername»}).toArray().length>0) { … print («Username exists»); … } else { … print («User does not exist»); }
или
if (db.users.find({username : «noSuchUsername»}).size()>0) { … print («Username exists»); … } else { … print («User does not exist»); }
findOne работает правильно, потому что, если данные не найдены, он возвращает null, который проходит в качестве ложного в логической проверке.