Search code examples
javascriptregexexpressnedb

Passing regex expression via API results in an error


I have created an API using Express in NodeJS which is using NeDB for its database.

I have examined the documentation and I can see that there is a way to filter results using regular expressions in order to carry out operations similar to "like" in SQL.

I am able to get the regular expressions to work when creating a hardcoded JSON object to use as the filter but when a filter is passed via my API, NeDB reports the following error:

Error: $regex operator called with non regular expression

My test database contains the following documents:

[
    {
        "test": "Hello",
        "other": "Goodbye",
        "_id": "9T0WaZ240q6ZK747"
    },
    {
        "test": "sup!",
        "other": "Ta ta",
        "extra": "something",
        "_id": "jLUzEZjLDVX1lmU5"
    }
]

When I execute a find() on the data using a hardcoded JSON filter it will return the correct result e.g.

{
     test: {
         $regex: /hell/i
     }
}

will return the first record in the database.

However, when I call the find() function from my API where I am passing the JSON object filter across, I receive the error mentioned before.

The filter from my API gets added as follows:

{ test: { '$regex': '/hell/i' } }

It looks like it may be the single quotes that are causing some issues but even after stripping them out it does not work. Either I get the same error or some other JSON parsing error.

I examined the code for NeDB and in the model.js file I added a line to print to the console what regular expression it had detected. In both cases (the hardcoded method that worked and the API method) the regular expression was returned as:

/hell/i

So it seems that NeDB is receiving an identical expression for both calls but for some reason throws an error with the API method.

Has anyone tried passing a JSON filter to an NeDB instance using the find() method and have it filter successfully?

I am using Postman for my API testing.


Solution

  • I have now managed to work out a sort-of solution. This is by no means perfect and still requires some more work and testing.

    I ended up modifying the model.js file within NeDB, more specifically the comparisonFunctions.$regex function. I added an additional check to see if the regular expression that gets passed in can be converted to a regular expression from its string form. The model.js file now looks as follows:

    comparisonFunctions.$regex = function (a, b) {
    
      if (!util.isRegExp(b)) {
    
        try {
    
          // convert the string based regex into an actual regular expression
          b = new RegExp(b.replace(/[\\/]/g, ""), 'i');
    
          // check again if it worked
          if (!util.isRegExp(b))
            throw new Error("$regex operator called with non regular expression");
    
        } catch {
    
          // we were not working with a regex
          throw new Error("$regex operator called with non regular expression");
    
        }
      }
    
      if (typeof a !== 'string') {
        return false
      } else {
        return b.test(a);
      }
    };
    

    So now if I pass this to my API:

    {
        "test": {
            "$regex": "/ell/"
        }
    }
    

    It will return the first document from the database where the test field == Hello

    Any recommendations on how to make this neater and/or feedback will be greatly appreciated.