MongoDB Text Search AND multiple search words
Asked Answered
P

4

50

I have an index on an array "keys" that I am using to provide full text functionality to my applicaiton.

With the release of 2.4.3, I'd like to utilize the "text" index type. I insured a "text" index type on my array "keys" and it seems to work SUPER fast (faster than my old keywords full text method).

The problem is, my app assumes that fields are inclusive (AND). By default, the text search ORs my parameters.

Does anyone know of a way to run a text search inclusively?

For example:

db.supplies.runCommand("text", {search:"printer ink"})

should return results with both printer and ink, instead of all results with either printer or ink.

Pyro answered 3/6, 2013 at 17:44 Comment(3)
I would really appreciate a solution which doesn't kill word stemming.Admirable
Could you find solution with word stemming?Slunk
There's a new and much better way to too accomplish this in MongoDB Atlas using Lucene: docs.atlas.mongodb.com/atlas-search It supports stemming and autocomplete.Abomb
P
85

Give a try to:

db.supplies.runCommand("text", {search:"\"printer\" \"ink\""})

Also, here's a quote from docs:

If the search string includes phrases, the search performs an AND with any other terms in the search string; e.g. search for ""twinkle twinkle" little star" searches for "twinkle twinkle" and ("little" or "star").

Parallelepiped answered 3/6, 2013 at 21:25 Comment(8)
Note that this throws cool features of the text index like word stemming into the trash whatsoever. If my text is These are some cool test entries here , I will find it with {$search:"entry"} but not with {$search:"\"entry\""}.Admirable
@Admirable Any way to do this without losing word stemming?Lysine
Here's an example in JS from a series of words, and with index creation, if that helps : var queryString = '\"' + q.split(' ').join('\" \"') + '\"'; var res = mycollection.find({ $text: { $search: queryString, $language: "fr" } }); and in mongo db.mycollection.createIndex( { "fieldName": "text"} )Juvenal
IMPORTANT NOTICE: works only with double quotes! With single quotes acts like standard $text search.Concoction
What if my text fields have a double-quote included, for instance when talking about appliances or whatnot: Kitchenaid KBSN608EPA 48" Refrigerator and I want the user to be able to find '48"' in the product title (because they WILL and DO use " to denote inches)Monofilament
It seems there is some issue with monogdb while searching multiple phrases. I have field having value 456 ABC. When I do multiple phrase search with keyword { "$search" : "\"45\" \"ABC\"" } or { "$search" : "\"456\" \"AB\"" }, It returns document. It shouldn't return result as both phrases are not exactly matchedPolychrome
With MongoDB 4.2 at least, it appears that stemming is actually maintained when performing a logical AND search using phrases for each term. For example, searching for \"Deconstruct\" returns results like "Deconstructed Pant". Not only that, but searching for something like \"Deconstruct\" \"Sh\" also narrows down results further to return only results that also contain "Sh", like "Deconstructed Shirt". Searching for \"Sh\" on its own however without another helper term returns no results.Protagonist
this is totally wrong. according to document: If the $search string includes a phrase and individual terms, text search will only match the documents that include the phrase.Kirkpatrick
L
7

You can wrap each word in double-quotes:

let keywords = ctx.params.query.split(/\s+/).map(kw => `"${kw}"`).join(' ');
match.$text = { $search: keywords, $caseSensitive: false };

There is a downside if the user inputs a quoted string this will not work. You'd have to parse out quoted strings first.

Lawn answered 15/3, 2017 at 4:59 Comment(0)
D
1

As @alecxe pointed out earlier, to do AND search on text index column you need to double quote each search word. Below is a quick one-liner for your requirement.

db.supplies.runCommand("text", {search: "printer ink".split(" ").map(str => "\""+str+"\"").join(' ')})
Dimphia answered 4/12, 2018 at 9:24 Comment(0)
B
-1

Here is a simple function I made to search using subwords in node. Hope it helps someone

Let's suppose a user search for pri nks so it should satisfy printer and inks but $text search doesn't allow for this so here is my simple function:

    var makeTextFilter = (text) => {
    var wordSplited = text.split(/\s+/);
    /** Regex generation for words */
    var regToMatch = new RegExp(wordSplited.join("|"), 'gi');
    let filter = [];
    searchFieldArray.map((item,i) => {
        filter.push({}); 
        filter[i][item] = {
            $regex: regToMatch,
            $options: 'i'
        }
    })

    return filter;
  }

and use it in your query like this

let query = {...query, $or: makeTextFilter(textInputFromUser)}
tableName.find(query, function (err, cargo_list)
Bergson answered 5/6, 2018 at 6:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.