Текстовый запрос Mongo $: возвращать документы "начиная с строки" перед другими
Скажем, у меня есть коллекция mongo с text index
в поле itemName
с этими тремя документами:
{
_id: ...,
itemName: 'Mashed carrots with big carrot pieces',
price: 1.29
},
{
_id: ...,
itemName: 'Carrot juice',
price: 0.79
},
{
_id: ...,
itemName: 'Apple juice',
price: 1.49
}
Затем я выполняю такой запрос:
db.items.find({ $text: { $search: 'Car' } }, { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } );
Как заставить mongo на возвращать документы, начинающиеся с "Car" (без учета регистра) до, возвращая любые другие документы, содержащие "Car" где-то в itemName
строка?
Итак, я хочу получить документы в следующем порядке:
[
{..., itemName: 'Carrot Juice', ...},
{..., itemName: 'Mashed carrots with big carrot pieces', ...}
]
Конечно, это предназначено для использования в функциональности поиска, поэтому имеет смысл показать пользователю элементы начиная с своей строки поиска, прежде чем показывать какие-либо другие элементы после этого.
До сих пор я использовал стандартное регулярное выражение, но производительность здесь, конечно, намного хуже! +, так как я должен искать регистр, нечувствительный, согласно документам, нормальное регулярное выражение вообще не использует никаких индексов?!
EDIT:
Кроме того, иногда поведение $text
очень странно.
Например, у меня около 10-15 предметов, где itemName
начинается со слова "Zwiebel".
Этот запрос
db.items.find({ $text: { $search: "Zwiebel" }, supplier_id: 'iNTJHEf5YgBPicTrJ' }, { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } );
работает как шарм и возвращает все эти документы, а этот запрос
db.items.find({ $text: { $search: "Zwie" }, supplier_id: 'iNTJHEf5YgBPicTrJ' }, { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } );
ничего не возвращает! Только изменив "Zwiebel" на "Zwie" в $search
.
Я действительно не понимаю, как это возможно?!
лучший, P
Ответы
Ответ 1
Решение состоит в использовании оператора $indexOfCP
, встроенного в MongoDB 3.4
Этот оператор возвращает индекс вхождения String в другой String и -1, если не существует события
как это работает:
- отфильтровать все документы, не содержащие "автомобиль" с регулярным выражением:
/car/gi
(нечувствительный к регистру)
- создайте поле с именем
index
, в котором хранится индекс "автомобиль" в itemName
- сортировать документы в поле
index
запрос будет выглядеть так:
db.items.aggregate([
{
$match:{
itemName:/car/gi
}
},
{
$project:{
index:{
$indexOfCP:[
{
$toLower:"$itemName"
},
"car"
]
},
price:1,
itemName:1
}
},
{
$sort:{
index:1
}
}
])
и это возвращает:
{ "_id" : 2, "itemName" : "Carrot juice", "price" : 0.79, "index" : 0 }
{ "_id" : 1, "itemName" : "Mashed carrots with big carrot pieces", "price" : 1.29, "index" : 7 }
Edit:
Для поведения индекса $text
это вполне нормально
Текстовый индекс tokenize текст с использованием разделителей (разделители по умолчанию - это пробел и пунктуация). Его можно использовать только для поиска целых миров, и поэтому он не будет работать для части слов
из текстовая документация mongodb
$text будет токенизировать строку поиска, используя пробелы и большинство пунктуации в качестве разделителей и выполнять логическое ИЛИ всех таких токенов в строке поиска.