Mongoose Text Search With And Operator
Solution 1:
Put quotation marks around the search terms to change the default behaviour to an 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);
});
Solution 2:
As Carlos mentioned, an acceptable workaround is to place double-quotes around single-word search terms to make them mandatory:
applebanana=> "apple""banana"
This produces similar behavior to the AND
operator of advanced search engines like Elasticsearch.
However, implementing this on a dynamic, user-generated query can get messy if you intend to support word exclusion via a preceding hyphen (-exclude
) or exact phrases ("several words wrapped in double quotes"
), both of which are valid syntax supported by $text
.
So, here's a function I wrote that wraps each separate word within the query with double quotes if it's not preceded by a hyphen or contained in an exact phrase.
Input:
apple banana "huge orange trees" -pineapple "lemon"
Output:
"apple""banana""huge orange trees" -pineapple "lemon"
Be sure to escape the output of this function with a preceding backslash before every double-quote. Then, pass it as the $search
parameter of your MongoDB find()
query.
function wrapSingleTermsWithDoubleQuotes(query) {
// Output variablevar 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 wordvar 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 charactersfor (var i = 0; i < query.length; i++) {
// Comfort variablevarchar = 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 quoteif (char == '"') {
// Avoid adding quotes until we encounter the phrase's closing quote
withinCustomPhrase = !withinCustomPhrase;
}
// Char is a negation operatorelseif (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 outputreturn output;
}
Post a Comment for "Mongoose Text Search With And Operator"