Search code examples
regexmongodbmongoose

Regex filtering in mongoose with partial words?


I am trying to filter result based on a string. For example- i have to find 'Sanam Suhag'.

When i type 's su' <= this will find the proper result.

But if first word have more then 1 alphabet then i will have to use full first word otherwise it will return empty array.

    router.get('/filter/:keywords', (req, res) => {

    console.log('Keyword recieved in backend ...', req.params.keywords);

    var regex = new RegExp(req.params.keywords, "i")
    var itemFound = Item.find({ name: regex, "status.active": true }, { 'name': 1 }).sort({ "updated_at": -1 }).sort({ "created_at": -1 }).limit(20);
    itemFound.exec((err, data) => {
        console.log(data);
        var result = [];
        if (!err) {
            if (data && data.length && data.length > 0) {
                data.forEach(item => {
                    let itemObj = item
                    result.push(itemObj)
                });
            }
            res.send(result)
        }
        if (err) {
         console.log(err);  
        }
    })
});

Need to find - Sanam Suhag

for 's su' query result - [{name - Sanam Suhag}]

For 'san suhag' query result - []


Solution

  • You should implement the logic to provide the Regex pattern according to the search input.

    To summarize the implementation:

    1. Split the search input (req.params.keywords) by space.

    2. If the first word (firstWord) has more than 1 character, you should use this pattern:

    ^(?:${firstWord})\s(?:${wordsAfterFirstWord})
    

    Demo Regex pattern 1 @ Regex 101

    1. Otherwise, you should use this pattern:
    ^(?:${firstWord}[\w]+)\s(?:${wordsAfterFirstWord})
    

    Demo Regex pattern 2 @ Regex 101

    let value = "Sanam Sunag";
    
    // Text search input: "s su"
    console.log("Search pattern: 's su', Result: ", getRegexForName("s su").exec(value));
    
    
    // Text search input: "sam su"
    console.log("Search pattern: 'sam su', Result: ", getRegexForName("sam su").exec(value));
    
    function getRegexForName(textSearch) {
        let regexPattern = null;
        
        if (!textSearch)
            return new RegExp("", "i");
    
        let words = textSearch.split(" ");
        let firstWord = words[0];
        let wordsAfterFirstWord = words.slice(1).join(' ');
        if (words.length == 1)
            return new RegExp(firstWord, "i"); // Or your desired regex pattern that match if the textSearch has single word only
    
        if (firstWord.length > 1)
            regexPattern = `^(?:${firstWord})\\s(?:${wordsAfterFirstWord})`;
        else
            regexPattern = `^(?:${firstWord}[\\w]+)\\s(?:${wordsAfterFirstWord})`;
    
        return new RegExp(regexPattern, "i");
    }

    For the caller:

    var regex = getRegexForName(req.params.keywords);