2015-04-11 3 views
31

Тип данных поля - String. Я хотел бы получить данные, где длина имени поля больше 40.Длина строки значения длины строки в mongoDB

Я пробовал эти запросы, но возвращал ошибку. 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

+1

Вы пытались использовать gt вместо> – gpullen

ответ

75

Для MongoDB 3.6 и новее:

$expr оператор позволяет использовать агрегирование выражения в языке запросов, таким образом, вы можете использовать использование оператора $strLenCP для проверки длины строки следующим образом:

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

Для MongoDB 3.4 и новее:

Вы также можете использовать структуру агрегации с оператором $redact трубопровода, что позволяет proccess логического условия с оператором в $cond и использует специальные операции $$KEEP, чтобы «сохранить» документ, где логическое условие истинно или $$PRUNE «удалить» документ, в котором условие было ложным.

Эта операция аналогична имеющей $project трубопровод, который выбирает поля в коллекции и создает новое поле, который содержит результат логического состояния запроса, а затем последующей $match, за исключением того, что $redact использования который является более эффективным.

Что касается логического условия, есть String Aggregation Operators, что вы можете использовать $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 оценивает Непро- операции $where запроса перед $where выражений и не- $where утверждения запроса могут использовать индекс. Более высокая производительность - сохранить длину строки в качестве другого поля, а затем вы можете индексировать или искать на ней; применение $where будет намного медленнее по сравнению с этим. Рекомендуется использовать выражения JavaScript и оператор $where в качестве последнего средства, когда вы не можете структурировать данные каким-либо другим способом или когда вы имеете дело с небольшим подмножеством данных .


Другой и более быстрый подход, который позволяет избежать использования оператора $where является основным оператором $regex. Рассмотрим следующий шаблон, который осуществляет поиск

db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2); 

Примечание - от docs:

Если индекс существует поле, то MongoDB соответствует регулярному выражение против значений в индекс, который может быть быстрее, чем сканирование коллекции . Дальнейшая оптимизация может произойти, если регулярное выражение является «префиксным выражением», что означает, что все потенциальные совпадения начинаются с одной и той же строки. Это позволяет MongoDB построить из этого префикса «диапазон» и соответствовать только этим значениям из индекса , которые попадают в этот диапазон.

Регулярное выражение является «выражением префикса», если она начинается с каретки (^) или левым якорем (\A), за которым следует строка простых символов. Например, регулярное выражение /^abc.*/ будет оптимизировано на , соответствующее только значениям индекса, начинающимся с abc.

Кроме того, в то время как /^a/, /^a.*/, и /^a.*$/ соответствуют эквиваленту строк , они имеют разные характеристики. Все эти выражения используют индекс, если существует соответствующий индекс; однако /^a.*/ и /^a.*$/ являются более медленными. /^a/ может остановить сканирование после , соответствующее префиксу.

+0

Все 3 вопроса работают нормально. Но первый принимает до 15. т. Е. «This.name.length> 15». Если мы даем 16 или выше, это дает ту же ошибку. –

+0

Если мы хотим выполнить то же самое для внутреннего документа, например profile.name, то можете ли вы предложить синтаксис для него. –

+1

Для встроенного поля документа попробуйте 'db.usercollection.find ({" profile.name ": {$ type: 2}, $ where:" this.profile.name.length> 40 "}). Limit (2); ' – chridam

1

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

Parent Collection 

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

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

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

} 
}}) 

 Смежные вопросы

  • Нет связанных вопросов^_^