Все мои записи имеют поле под названием «картинки». Это поле представляет собой массив строк.
Теперь я хочу 10 последних записей, где этот массив НЕ пуст.
Я гуглил вокруг, но, как ни странно, я не нашел много на этом. Я прочитал опцию $ where, но мне было интересно, насколько она медленная для нативных функций и есть ли лучшее решение.
И даже тогда это не работает
ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()
Ничего не возвращает Оставление this.pictures
без бита длины работает, но затем оно также возвращает пустые записи, конечно.
mongoengine
ME.find({ pictures: { $gt: [] } })
ОПАСНО, даже в новых версиях MongoDB. Если у вас есть индекс в поле списка, и этот индекс используется во время запроса, вы получите неожиданные результаты. Например:db.doc.find({'nums': { $gt: [] }}).hint({ _id: 1 }).count()
возвращает правильный номер, аdb.doc.find({'nums': { $gt: [] }}).hint({ nums: 1 }).count()
возвращает0
.После более тщательного изучения, особенно в документах mongodb, и загадки вместе, это был ответ:
источник
pictures
поля.Это также может работать для вас:
источник
pictures.2
существует, ноpictures.1
не существует ?$exists
Оператор является логическим, а не смещением. @tenbatsu следует использоватьtrue
вместо1
.Would there ever be a case where pictures.2 exists but pictures.1 does not?
Да, это может случиться.pictures
это вспомогательный документ, а не массив. напримерpictures: {'2': 123}
pictures
.При запросе вы заботитесь о двух вещах - точности и производительности. Имея это в виду, я протестировал несколько разных подходов в MongoDB v3.0.14.
TL; DR
db.doc.find({ nums: { $gt: -Infinity }})
- самый быстрый и самый надежный (по крайней мере, в версии MongoDB, которую я тестировал).РЕДАКТИРОВАТЬ: Это больше не работает в MongoDB v3.6! Смотрите комментарии под этим постом для потенциального решения.
Настроить
Я вставил 1k документов без поля списка, 1k документов с пустым списком и 5 документов с непустым списком.
Я признаю, что этого недостаточно для того, чтобы серьезно относиться к производительности, как в приведенных ниже тестах, но достаточно для представления правильности различных запросов и поведения выбранных планов запросов.
тесты
db.doc.find({'nums': {'$exists': true}})
возвращает неправильные результаты (для того, что мы пытаемся достичь).-
db.doc.find({'nums.0': {'$exists': true}})
возвращает правильные результаты, но это также медленно, используя полное сканирование коллекции (COLLSCAN
этап уведомления в объяснении).-
db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}})
возвращает неверные результаты. Это из-за недопустимого сканирования индекса, при котором нет документов. Скорее всего, он будет точным, но медленным без индекса.-
db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}})
возвращает правильные результаты, но производительность плохая. Технически он выполняет сканирование индекса, но затем все равно перемещает все документы, а затем должен их отфильтровать).-
db.doc.find({'nums': { $exists: true, $ne: [] }})
возвращает правильные результаты и немного быстрее, но производительность все еще не идеальна. Он использует IXSCAN, который только продвигает документы с существующим полем списка, но затем должен отфильтровать пустые списки один за другим.-
db.doc.find({'nums': { $gt: [] }})
ОПАСНО, ПОТОМУ ЧТО ЗАВИСИТ ОТ ИСПОЛЬЗОВАННОГО ИНДЕКСА, МОЖЕТ ДАТЬ НЕОБХОДИМЫЕ РЕЗУЛЬТАТЫ. Это из-за недопустимого сканирования индекса, который не продвигает никаких документов.-
db.doc.find({'nums.0’: { $gt: -Infinity }})
возвращает правильные результаты, но имеет плохую производительность (использует полное сканирование коллекции).-
db.doc.find({'nums': { $gt: -Infinity }})
удивительно, это работает очень хорошо! Это дает правильные результаты и быстро, продвигая 5 документов от фазы сканирования индекса.источник
seen_events
массив строк, который также индексируется. Выполняя поиск{ $gt: -Infinity }
, я сразу получаю 0 документов. Используя{ $exists: true, $ne: [] }
я получаю более вероятные документы в 1,2 млн., Причем на этапе FETCH тратится много времени: gist.github.com/N-Coder/b9e89a925e895c605d84bfeed648d82cdb.test_collection.find({"seen_events.0": {$exists: true}})
это плохо , потому что он использует для сбора сканирования 2..db.test_collection.find({seen_events: {$exists: true, $ne: []}})
Является плохо, потому что его IXSCAN соответствует всем документам, а затем выполняется фильтрация в фазе медленного FETCH. 3. То же самое дляdb.test_collection.find({seen_events: {$exists: true, $not: {$size: 0}}})
4. Все остальные запросы возвращают неверные результаты.seen_events
содержат строки, вы можете использовать это:db.test_collection.find({seen_events: {$gt: ''}}).count()
. Чтобы подтвердить, что это хорошо работает, проверьтеdb.test_collection.find({seen_events: {$gt: ''}}).explain(true).executionStats
. Вы можете, вероятно, обеспечить соблюдение , что видел события строки с помощью проверки схемы: docs.mongodb.com/manual/core/schema-validationНачиная с версии 2.6, другой способ сделать это - сравнить поле с пустым массивом:
Тестирование в оболочке:
Таким образом, он правильно включает документы, в которых
pictures
есть хотя бы один элемент массива, и исключает документы, в которыхpictures
пустой массив, а не массив или отсутствует.источник
db.ME.createIndex({ pictures: 1 })
а затемdb.ME.find({pictures: {$gt: []}})
возвращает ноль результатов, по крайней мере, в MongoDB v3.0.14Вы можете использовать любое из следующих действий для достижения этой цели.
Оба также заботятся о том, чтобы не возвращать результат для объектов, в которых нет запрошенного ключа:
источник
Получить все и только документы, где 'pictures' - это массив, а не пустой
Если используется версия MongoDb до 3.2 , используйте
$type: 4
вместо$type: 'array'
. Обратите внимание, что это решение даже не использует размер $ , поэтому с индексами проблем нет («Запросы не могут использовать индексы для части $ size запроса»)Другие решения, в том числе следующие (принятый ответ):
являются неправильно , потому что они возвращают документы , даже если, например, «картинка» есть
null
,undefined
, 0 и т.д.источник
Используйте
$elemMatch
оператора: согласно документации$elemMatches
проверяет, является ли значение массивом и не является ли оно пустым Так что запрос будет что-то вродеME.find({ pictures: { $elemMatch: {$exists: true }}})
PS Вариант этого кода можно найти в курсе M121 Университета MongoDB.
источник
Вы также можете использовать вспомогательный метод Exists поверх оператора Mongo.
источник
используйте $ where и передайте this.field_name.length, которое возвращает размер поля массива, и проверьте его, сравнив с числом. если какой-либо массив имеет любое значение, чем размер массива должен быть по крайней мере 1. таким образом, все поля массива имеют длину больше единицы, это означает, что в этом массиве есть некоторые данные
источник
Просто, это работало для меня.
источник