Best way to perform a full text search in MongoDB and Mongoose
Asked Answered
B

3

129

I'm searching on Google since days and I tried many things but I still can not perform a good full text search on my user collection.

I tried ElasticSearch but was pretty impossible to query and paginate...

I tried many plugins for Mongoose like ElMongo, mongoose-full-text, Mongoosastic, etc... everyone are really bad documented and I don't know how to perform a good full text search.

So, my collection is a normal collection:

user = {
  name: String,
  email: String,
  profile: {
    something: String,
    somethingElse: String
  }
}

I have a search input in a page with a simple POST, if I type hello world what I need is to search on the entire collection fields the matching words of my search query and get the results.

It will be really nice also to have options to handle a pagination like 10 items per page or something...

What is the best solution to achieve this? I'm using MongoDB 2.6.* with Mongoose, NodeJS and ExpressJS.

Thanks.

Barrie answered 27/2, 2015 at 21:59 Comment(0)
A
294

You can add a text index to your Mongoose schema definition that lets you use the $text operator in your find queries to search all fields included in the text index.

To create an index to support text search on, say, name and profile.something:

var schema = new Schema({
  name: String,
  email: String,
  profile: {
    something: String,
    somethingElse: String
  }
});
schema.index({name: 'text', 'profile.something': 'text'});

Or if you want to include all string fields in the index, use the '$**' wildcard:

schema.index({'$**': 'text'});

This would enable you to perform a paged text search query like:

MyModel.find({$text: {$search: searchString}})
       .skip(20)
       .limit(10)
       .exec(function(err, docs) { ... });

For more details, read the full MongoDB Text Indexes documentation.

Aircraft answered 27/2, 2015 at 22:52 Comment(6)
Thanks for your answer. Does not lower the MongoDB performance doing this? One more question please: Can I also choose the fields to index?Barrie
@AyeyeBrazo I updated the anser to show how to choose the fields to index. Adding any index adds overhead during inserts and updates, as well as added storage requirements, so that must always be considered.Aircraft
after long searching, your answer is king!Ornie
Is there possibility to make "wordA AND wordB" search? And search part of words?Clarisclarisa
@Clarisclarisa check docs.mongodb.com/manual/reference/operator/query/text/… for case sensitive searchRena
$text is not supported in my case, Can we use wild cards for the same scenario?Mycetozoan
M
4

This is not an extra answer but an addUp, but if the above answer by JohnnyHK is giving you an empty array [] .

  1. Try something basic first without limit and skip

    const results = await MyModel.find({ $text: { $search: "text" } });

  2. Please check if the index was created properly using mongosh using db.stories.getIndexes() or compass GUI both attached. Else create one via COMPASS GUI or via mongosh using docs

compasss

  1. Then try changing searchText multiple times and try.
  2. Even after all this it took me 7- 8 runs of same code to get proper results,
Malvia answered 1/4, 2022 at 23:9 Comment(0)
V
0

let results = await User.find( {$text: {$search: "text that you want to search for"}}, {score: {$meta: "textScore"}}) .sort({score:{$meta:"textScore"}}); where User is the schema that you have created and the function in which this is coded should be made async.

Vano answered 1/3 at 23:1 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Gownsman

© 2022 - 2024 — McMap. All rights reserved.