Ответ 1
Для MongoDB 3.6 и новее:
Оператор $expr
позволяет использовать выражения агрегации в языке запросов, поэтому вы можете использовать оператор $strLenCP
для проверки длины строки следующим образом:
db.usercollection.find({
"name": { "$exists": true },
"$expr": { "$gt": [ { "$strLenCP": "$name" }, 40 ] }
})
Для MongoDB 3.4 и новее:
Вы также можете использовать структуру агрегации с оператором конвейера $redact
которая позволяет $redact
логическое условие с помощью оператора $cond
и использовать специальные операции $$KEEP
чтобы "хранить" документ, где логическое условие истинно или $$PRUNE
"удалить" документ, где условие было ложным.
Эта операция похожа на конвейер $project
который выбирает поля в коллекции и создает новое поле, которое содержит результат запроса логического условия и последующего $match
, за исключением того, что $redact
использует один этап конвейера, который более эффективный.
Что касается логического условия, есть операторы агрегирования строк, которые можно использовать оператор $strLenCP
для проверки длины строки. Если длина равна указанному значению в $gt
, то это истинное совпадение, и документ "сохраняется". В противном случае он "обрезается" и отбрасывается.
Попробуйте запустить следующую агрегатную операцию, которая демонстрирует вышеуказанную концепцию:
db.usercollection.aggregate([
{ "$match": { "name": { "$exists": true } } },
{
"$redact": {
"$cond": [
{ "$gt": [ { "$strLenCP": "$name" }, 40] },
"$$KEEP",
"$$PRUNE"
]
}
},
{ "$limit": 2 }
])
Если вы используете $where
, попробуйте выполнить запрос без скобок:
db.usercollection.find({$where: "this.name.length > 40"}).limit(2);
Лучше было бы проверить наличие поля, а затем проверить длину:
db.usercollection.find({name: {$type: 2}, $where: "this.name.length > 40"}).limit(2);
или же:
db.usercollection.find({name: {$exists: true}, $where: "this.name.length >
40"}).limit(2);
MongoDB оценивает non- $where
операции запроса перед $where
выражения и non- $where
операторы запроса могут использовать индекс. Гораздо лучшая производительность - хранить длину строки как другое поле, а затем вы можете индексировать или искать по ней; применение $where
будет намного медленнее по сравнению с этим. Рекомендуется использовать выражения JavaScript и оператор $where
в качестве крайней меры, когда вы не можете структурировать данные каким-либо другим способом или когда имеете дело с небольшим подмножеством данных.
Другой и более быстрый подход, позволяющий избежать использования оператора $where
оператора $regex
. Рассмотрим следующую схему поиска
db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2);
Примечание. Из документов:
Если для поля существует индекс, то MongoDB сопоставляет регулярное выражение со значениями в индексе, что может быть быстрее, чем сканирование коллекции. Дальнейшая оптимизация может произойти, если регулярное выражение является "выражением префикса", что означает, что все потенциальные совпадения начинаются с одной и той же строки. Это позволяет MongoDB построить "диапазон" из этого префикса и сопоставлять только те значения из индекса, которые попадают в этот диапазон.
Регулярное выражение - это "префиксное выражение", если оно начинается с каретки
(^)
или левого якоря(\A)
, за которым следует строка простых символов. Например, регулярное выражение/^abc.*/
будет оптимизировано путем сопоставления только со значениями из индекса, начинающегося сabc
.Кроме того, хотя
/^a/,/^a.*/,
и/^a.*$/
соответствуют эквивалентным строкам, они имеют разные характеристики производительности. Все эти выражения используют индекс, если существует соответствующий индекс; однако/^a.*/
и/^a.*$/
работают медленнее./^a/
может остановить сканирование после сопоставления префикса.