35

I would like to make query MongoDB for documents based on a regex expression that I contruct. For e.g I have constructed a simple regex as follows that is a combination of a random letter and a random number for in Nodejs

var randnum = Math.floor((Math.random() * 10) + 1);
var alpha = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','X','Y','Z'];
var randletter = alpha[Math.floor(Math.random() * alpha.length)];
var val = randletter + randnum + '.*;

I have tried various combinations for the regex variable like

var stream = collection.find({"FirstName": /val/).stream();
&&
var stream = collection.find({"FirstName": /$val/).stream();
&&
var stream = collection.find({"FirstName": {$in : [{$regex:val}]}}).stream()
&&
var stream = collection.find({"FirstName": {$in : [{$regex:$val}]}}).stream()

None o it seem to work. However when I write the actual regex I get the records for e.g.

var stream = collection.find({"FirstName": /J.*/).stream();

Any help will be appreciated.

Thanks Ganesh

Tinniam V. Ganesh
  • 1,979
  • 6
  • 26
  • 51
  • Wizard, Thanks. However, this did not seem to work.var stream = collection.find({"FirstName": {$regex:val}}).stream(); stream.on("data", function(item) results.push(item); – Tinniam V. Ganesh Nov 02 '14 at 15:03
  • Any error occurs, or just doesn't get the expected result? Example of a document stored in the database may be helpful. – Wizard Nov 02 '14 at 15:14

7 Answers7

55

I was having same problem with my title and after lots of searching, i found this answer Here,

var search = 'Joe';
db.users.find(name: /^search/)
db.users.find(name: {$regex: /^search/});
db.users.find(name: {$regex: "/^" + search + "/"});

The queries above won’t return anything. The solution to this little problem is quite simple:

db.users.find(name: new RegExp(search)) //For substring search, case sensitive. 
db.users.find(name: new RegExp('^' + search + '$')) //For exact search, case sensitive
db.users.find(name: new RegExp(search, ‘i')) //For substring search, case insensitive
db.users.find(name: new RegExp('^' +search + '$', 'i')); //For exact search, case insensitive

Other flags or properties can be added base on reference here

Hamza Khan
  • 1,321
  • 11
  • 15
  • 2
    `db.users.find(name: {$regex: "/^" + search + "/"});` exactly what I needed – rotimi-best May 13 '19 at 16:31
  • 1
    For me it didn't work using the `/`. Like in this example: `var name = '.*'+user.name+'.*' found = db.users.findOne({ 'name': {$regex: name} }) ` – Guilherme Sampaio Feb 09 '20 at 22:30
  • 1
    i was exactly looking for db.users.find(name: new RegExp('^' +search + '$', 'i')); thanks.. – Hrishikesh Baidya Jul 27 '20 at 13:31
  • Hamza : I am facing an issue with `case insensitive` and `exact search` . The rule I have added is as follows {name: new RegExp('^' + search + '$' , "i")} . The prolem is that when I search `test...` (with dots, which I need since there is entry with dots) , I got results `test123`, `test333` etc.... How can I get only entry `test...` – Ajith Jan 20 '21 at 06:31
  • It's not working with MongoDB. It's passing "search" as a string as supposed to value of the variable. – Hardik Raval Mar 28 '22 at 12:26
49

You need to create a regular expression object from the string using the RegExp constructor as the /.../ syntax is only for use with literals.

var stream = collection.find({"FirstName": new RegExp(val)}).stream();
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
  • 1
    JohnnyHK - That worked awfully well. The changes I made were var val = randletter + ".*" + randnum + ".*"; var stream = collection.find({"FirstName": new RegExp(val)}).stream(); Thanks Ganesh – Tinniam V. Ganesh Nov 02 '14 at 15:15
  • I have tried what you suggested, but it didn't seem to work. What I have to do is, let pattern = '/^\/'+ cat + '/'; col.find({name: new RegExp(pattern)}) where cat is a variable whose value I am concatenating to create pattern for matching. – Avani Khabiya Oct 22 '20 at 05:41
  • Remove the `/` characters from `pattern` and it will work. @AvaniKhabiya – JohnnyHK Oct 22 '20 at 12:46
11

Use the following code to use dynamic value in regex with or operations

{$match: { $or: [{ 'title': { $regex:  request.query.val, $options: 'i'} }, { 'skills_required': { $regex:  request.query.val, $options: 'i'} }] }},
  • $or: [{users: { $elemMatch: { name: { $regex: `${filters.userName}`, $options: 'i' } } },}]; . . .. . . .great answer! also works with string interpolation e.g. – aris May 17 '23 at 20:29
9

If you want to use the variable val as a parameter of the query part, you can use $regex, for example:

collection.find({"FirstName": {$regex:val}})

It is not allowed to put $regex in $in operator according to the manual.

If you want to put regular expression object in $in operator, you have to use JavaScript regular expression object, for example:

collection.find({"FirstName": {$in: [/abc/, /123/]}})

By the way, val in /val/ is constant string, not the variable as you defined above.

Wizard
  • 4,341
  • 1
  • 15
  • 13
  • Hi -Thanks. But it did not work - var val = randletter + randnum + '.*'; var stream = collection.find({"FirstName": {$regex:val}}).stream(); Regards Ganesh – Tinniam V. Ganesh Nov 02 '14 at 15:18
  • @TinniamV.Ganesh, What's value of **FirstName** in database? Or maybe just no items can satisfy your query needs? – Wizard Nov 02 '14 at 15:23
  • 1
    Wizard - Firstname is just a string of letters and numbers. I tried it a couple of times it always returned an empty set. The other version var stream = collection.find({"FirstName": new RegExp(val)}).stream(); worked. Thanks anyway. Regards Ganesh – Tinniam V. Ganesh Nov 02 '14 at 16:35
  • @TinniamV.Ganesh, Thanks for the reply. I think I missed some details about your circumstances which do not support $regex. – Wizard Nov 03 '14 at 00:32
8

If your regex includes a variable, make sure to escape it.

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

This can be used like this

new RegExp(escapeRegExp(searchString), 'i')

Or in a mongoDb query like this

{ '$regex': escapeRegExp(searchString) }

Posted same comment here

Scott Wager
  • 758
  • 11
  • 9
3
let test = `what your regex should search`;

collection.find({
    fieldName: {$regex: test}
}).then(result => red.send(result));

// tested on mongoose but should work on mongodb too

Chukwuemeka Maduekwe
  • 6,687
  • 5
  • 44
  • 67
0

My use case was to fetch results STARTS WITH a given query, and below solution worked for me.

let q = '^' + query;
return await User.find({ name: { $regex: q, $options: 'i' } }).select('name').limit(10);
Hardik Raval
  • 3,406
  • 1
  • 26
  • 28