所以我要做的是用mongoose和mongoDb进行“AND”搜索,但结果来自“OR”搜索。这有什么设置吗?这就是查询的样子:
exampleModel.find({
$text: {
$search: searchParams
}
}, {
score: {
$meta: "textScore"
}
}, { lean: true }).select(exampleViewModel).limit(1000).sort({
score: {
$meta: 'textScore'
}
}).exec(function (err, results) {
next(null, results);
});
让我们假设searchParams = restaurant london;
这将在包含“restaurant”或“london”字样的文档中产生结果。 我希望它在包含“restaurant”和“london”字样的文档中产生结果。
答案 0 :(得分:1)
在搜索字词周围加上引号,将默认行为更改为AND。
https://docs.mongodb.org/manual/reference/operator/query/text/#phrases
exampleModel.find({
$text: {
$search: "\"restaurant\" \"london\""
}
}, {
score: {
$meta: "textScore"
}
}, { lean: true }).select(exampleViewModel).limit(1000).sort({
score: {
$meta: 'textScore'
}
}).exec(function (err, results) {
next(null, results);
});
答案 1 :(得分:1)
正如卡洛斯所提到的,一个可接受的解决方法是在单字搜索术语中加上双引号,使其成为强制性的:
apple banana => "apple" "banana"
这会产生与Elasticsearch等高级搜索引擎的AND
运算符类似的行为。
但是,如果您打算通过前面的连字符(-exclude
)或精确短语("several words wrapped in double quotes"
)来支持单词排除,那么在动态的,用户生成的查询中实现此操作会变得混乱是$text
支持的有效语法。
所以,这里是我编写的一个函数,如果查询中的每个单独的单词前面没有连字符或包含在一个精确的短语中,则用查询包装每个单独的单词。
<强>输入:强>
apple banana "huge orange trees" -pineapple "lemon"
<强>输出:强>
"apple" "banana" "huge orange trees" -pineapple "lemon"
确保在每个双引号之前使用前面的反斜杠转义此函数的输出。然后,将其作为MongoDB $search
查询的find()
参数传递。
function wrapSingleTermsWithDoubleQuotes(query) {
// Output variable
var output = "";
// Keep track of whether to ignore the current word due to the negation operator (-minus)
var ignoreCurrentWord = false;
// Keep track of whether we're inside a custom phrase in the query ("exact match")
var withinCustomPhrase = false;
// Keep track of whether we need to close a double quote that we opened for the current word
var openedDoubleQuote = false;
// Remove all double spacing from the query (we may need a few iterations for this to work)
while (query.indexOf(' ') != -1) {
// Replace all occurrences of double spacing with single spacing
query = query.replace(/ /g, ' ');
}
// Trim leading and trailing spaces from the query to normalize the input
query = query.trim();
// Start traversing query characters
for (var i = 0; i < query.length; i++) {
// Comfort variable
var char = query[i];
// Not yet wrapping a term with double quotes?
if (!openedDoubleQuote) {
// Not ignoring the current word already (due to an operator) and not within a custom phrase?
if (!ignoreCurrentWord && !withinCustomPhrase) {
// Char is not a quote or negation operator?
if (char != '"' && char != '-') {
// This is most likely a single term, let's insert an opening double quote
output += '"';
// Mark this as true so we remember to close the double-quote when the word's done
openedDoubleQuote = true;
}
else {
// Char is a quote
if (char == '"') {
// Avoid adding quotes until we encounter the phrase's closing quote
withinCustomPhrase = !withinCustomPhrase;
}
// Char is a negation operator
else if (char == '-') {
// Ignore the current word (don't try to wrap it with double quotes)
ignoreCurrentWord = true;
}
}
}
else {
// Ignoring the current word or phrase -- check if we reached the end of the current word (space)
if (char == ' ') {
// In case this was a negative word, it's over now
ignoreCurrentWord = false;
// Were we inside a custom phrase, the current char is a space, and the previous char was a double quote?
if (withinCustomPhrase && i > 0 && query[i - 1] == '"') {
// No longer inside a the custom phrase (since we encountered a closing double-quote)
withinCustomPhrase = false;
}
}
}
}
else {
// Within a single term currently -- is current char a space, indicating the end of the single term?
if (char == ' ') {
// Add a closing double quote to finish wrapping the single term
output += '"';
// We closed our own double-quote
openedDoubleQuote = false;
}
}
// Add current char to output (we never omit any query chars, only append double-quotes where necessary)
output += char;
}
// Reached the end of the string but still got a quote to close?
if (openedDoubleQuote) {
// Add the final double quote
output += '"';
}
// Return algorithm output
return output;
}