"текстов индекс" и търсене наистина е най-добрият вариант тук, стига да търсите цели думи.
Добавянето на текстов индекс към вашата дефиниция на схема е доста просто:
BookSchema.index(
{
"name": "text",
"description": "text",
"body": "text"
},
{
"weights": {
"name": 5,
"description": 2
}
}
)
Това ви позволява да извършвате прости търсения с "зададено" тегло на полетата:
Book.find({ "$text": { "$search": "Holiday School Year" } })
.select({ "score": { "$meta": "textScore" } })
.sort({ "score": { "$meta": "textScore" } })
.exec(function(err,result) {
}
);
Където всеки съвпадащ термин ще бъде разглеждан спрямо полето, в което е намерен, което дава най-голяма тежест и брой срещания.
Присвояването на теглата е прикрепено към "индекса", така че дефинирането се прави веднъж и не може да се променя. Друго ограничение е, че при „търсене на текст“ не се разглеждат „частични“ думи. Например "ci" не съвпада с "City" или "Citizen" и за такова нещо ще ви трябва регулярен израз вместо това.
Ако имате нужда от повече гъвкавост от тази или като цяло трябва да можете да променяте динамично теглото на резултатите, тогава имате нужда от нещо като рамка за агрегиране или mapReduce.
Рамката за агрегиране обаче не може да извърши "логично" съвпадение операция (може да филтрира въпреки $match
оператор, но не и „логическо“ съвпадение) на „регулярен израз“ с вашите условия. Можете обаче да работите с отделни думи и "точни" съвпадения, ако това ви устройва.
Book.aggregate(
[
{ "$match": {
"$or": [
{ "name": /Holiday/ },
{ "description": /Holiday/ },
{ "body": /Holiday/ }
]
}},
{ "$project": {
"name": 1,
"description": 1,
"body": 1,
"score": {
"$add": [
{ "$cond": [{ "$eq": [ "$name", "Holiday" ] },5,0 ] },
{ "$cond": [{ "$eq": [ "$description", "Holiday" ] },2,0 ] },
{ "$cond": [{ "$eq": [ "$body", "Holiday" ] },1,0 ] }
]
}
}},
{ "$sort": { "score": -1 } }
],
function(err,results) {
}
)
Тъй като тръбопроводът за агрегиране използва структура от данни за заявка, където можете да промените параметрите за тегло на всяко изпълнение до това, от което се нуждаете в момента.
MapReduce споделя подобен принцип, където можете да включите изчислен "резултат" в част от първичния ключ, излъчван като водещ елемент. MapReduce естествено сортира целия вход, излъчен от този ключ, като оптимизация за подаване към функция за намаляване. Въпреки това не можете допълнително да сортирате или "ограничите" такъв резултат.
Обикновено това са вашите опции, които трябва да разгледате и да решите коя е най-подходяща за вашия случай.