Подтвердить что ты не робот

Длина значения длины строки в mongoDB

Тип данных поля - String. Я хотел бы получить данные, где длина имени поля больше 40.

Я пробовал эти запросы, но возвращал ошибку. 1.

db.usercollection.find(
{$where: "(this.name.length > 40)"}
).limit(2);

output :error: {
    "$err" : "TypeError: Cannot read property 'length' of undefined near '40)' ",
    "code" : 16722
}

это работает в версии 2.4.9. Но моя версия 2.6.5

4b9b3361

Ответ 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/ может остановить сканирование после сопоставления префикса.

Ответ 2

Вот один из способов в mongodb вы можете достичь этого.

db.usercollection.find({ $where: 'this.name.length < 4' })

Ответ 3

У меня был похожий сценарий, но в моем случае строка не является атрибутом 1-го уровня. Он находится внутри объекта. Здесь я не нашел подходящего ответа. Поэтому я решил поделиться своим решением со всеми вами (надеюсь, это поможет любому, у кого есть подобные проблемы).

Parent Collection 

{
"Child":
{
"name":"Random Name",
"Age:"09"
}
}

Пример: если нам нужно получить только коллекции, длина которых имеет длину имени дочернего имени, более 10 символов.

 db.getCollection('Parent').find({$where: function() { 
for (var field in this.Child.name) { 
    if (this.Child.name.length > 10) 
        return true;

}
}})

Ответ 4

Запросы с $where и $expr выполняются медленно, если документов слишком много.

Использование $regex намного быстрее, чем $where, $expr.

db.usercollection.find({ 
  "name": /^[\s\S]{40,}$/, // name.length >= 40
})

or 

db.usercollection.find({ 
  "name": { "$regex": "^[\s\S]{40,}$" }, // name.length >= 40
})

Этот запрос имеет то же значение, что и

db.usercollection.find({ 
  "$where": "this.name && this.name.length >= 40",
})

or

db.usercollection.find({ 
    "name": { "$exists": true },
    "$expr": { "$gte": [ { "$strLenCP": "$name" }, 40 ] } 
})

Я проверил каждый запрос для моей коллекции.

# find
$where: 10529.359ms
$expr: 5305.801ms
$regex: 2516.124ms

# count
$where: 10872.006ms
$expr: 2630.155ms
$regex: 158.066ms