Skip to content Skip to sidebar Skip to footer

Mongoose Text Search With And Operator

So what I'm trying to do is making a 'AND' search with mongoose to mongoDb, but the results is from a 'OR' search. Is there a setting for this? This is how query looks like: exampl

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"