AndrewLeonardi
AndrewLeonardi

Reputation: 3512

Fuzzy Searching with Mongodb?

I have managed to set up a search feature in my mongodb app. See the code below. This works very well however it only returns exact results. How would I change my code to make it accept more "fuzzy" search results? Thanks!

router.get("/", function(req, res){
    if (req.query.search) {
       Jobs.find({"name": req.query.search}, function(err, foundjobs){
       if(err){
           console.log(err);
       } else {
          res.render("jobs/index",{jobs:foundjobs});
       }
    }); 
    }

  Jobs.find({}, function(err, allJobs){
       if(err){
           console.log(err);
       } else {
          res.render("jobs/index",{jobs:allJobs});
       }
    });
});

Upvotes: 36

Views: 56274

Answers (5)

Nice-Guy
Nice-Guy

Reputation: 1524

This is an updated answer that comes on the heels of a new product in MongoDB that was not released at the time of the original post. MongoDB now has a feature where you can deploy Apache Lucene indexes to get robust fuzzy search functionality, and other features like synonyms, highlighting and autocomplete.

Below is the syntax as posted here in another answer I had.

{
  $search: {
    "index": <index name>, // optional, defaults to "default"
    "text": {
      "query": "queryText",
      "path": "<fields-to-search>",
      "fuzzy": {
         "maxEdits": 2
       }
    }
  }
}

Upvotes: 1

raphael
raphael

Reputation: 21

if you are using atlas go to the index tab create an index for your database then you can use aggregate for a more powerful fuzzy search.

Jobs.aggregate([
    {
        $search: {
            "index": "default",
            "text": {
                "path": "name",
                "query": req.query.search,
            }
        }
    },
], (err: any, data: any) => {
    if (err) {
        res.status(500).send(err);
    }
    else {
        res.status(200).send(data);
    }
}).limit(20)

Upvotes: 0

Shreyesh Desai
Shreyesh Desai

Reputation: 719

You can use the Mongo DB Atlas feature where you can search your text based on different Analyzers that MongoDB provides. And you can then do a search like this: Without the fuzzy object, it would do a full-text-match search.

$search:{
 {
  index: 'analyzer_name_created_from_atlas_search',
  text: {
    query: 'Russ has denied involvement in the case',
    path: 'sentence',
    fuzzy:{
      maxEdits: 2
    }
  }
 }
}

Upvotes: 4

Vasileios Pallas
Vasileios Pallas

Reputation: 4877

I know this is an old thread, but I made a plugin which is based on this article.

mongoose-fuzzy-searching

(It uses $text query operator instead of $regex, for faster results)

The below example just searches for events based on title and city

const mongoose_fuzzy_searching = require('mongoose-fuzzy-searching');

const schema = {
    title: {
        type: String,
        trim: true,
        required: true,
    },
    description: {
        type: String,
        trim: true,
    },
    city: {
        type: String,
    },
    address: {
        type: String,
    }
};

const EventsSchema = mongoose.Schema(schema);
EventsSchema.plugin(mongoose_fuzzy_searching, {fields: ['title', 'city']});

const Events = mongoose.model('Events', EventsSchema);

Events.fuzzySearch('Nodejs meetup').then(console.log).catch(console.error);

Upvotes: 20

the holla
the holla

Reputation: 816

I believe that to do "fuzzy" search you will need to use regex. This should accomplish what you're looking for (escapeRegex function source here):

function escapeRegex(text) {
    return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};

router.get("/", function(req, res) {
    if (req.query.search) {
       const regex = new RegExp(escapeRegex(req.query.search), 'gi');
       Jobs.find({ "name": regex }, function(err, foundjobs) {
           if(err) {
               console.log(err);
           } else {
              res.render("jobs/index", { jobs: foundjobs });
           }
       }); 
    }
}

That being said, your application can experience performance issues when querying mongo by regex. Using a library like search-index for search could help optimize your application's performance, with the added benefit of searching word stems (like returning "found" from "find").


UPDATE: My original answer included a simple regular exression that would leave your application vulnerable to a regex DDoS attack. I've updated with a "safe" escaped regex.

Upvotes: 44

Related Questions