Two identical $regex declarations behave differently in Mongo shell - regex

According to $regex documentation, the following $regex declarations are identical:
{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ <field>: { $regex: 'pattern', $options: '<options>' } }
{ <field>: { $regex: /pattern/<options> } }
I was playing around with the zips.json dataset in the Mongo shell, and tried to find cities that begin and end with the same character. However, the query returned different results depending on whether I used 'pattern' or /pattern/.
$ mongo
MongoDB shell version: 3.0.1
connecting to: test
> db.version()
3.0.1
> db.zips.find( { city: { $regex: '^(.).*\1$' } }, { city: true } ).count()
0
> db.zips.find( { city: { $regex: /^(.).*\1$/ } }, { city: true } ).count()
1418
Is there any difference in behavior despite what the documentation says? Something to do with the latter being a JavaScript regex perhaps?

Silly me. In the first declaration, I should have escaped the backslash like this:
db.zips.find( { city: { $regex: '^(.).*\\1$' } }, { city: true } ).count()

Related

How to search and find multiple field values... using MongoDB and I tried with regex

I am trying to find 3 different field values while searching with .find() method and it gives either complete data or only one.
This is the code I have given:
const search = req.query.search || "";
const Rest = await Restaurant.find(
{name:{$regex:search,$options:"i"}},
{locality:{$regex:search,$options:'i'}},
{"cuisine.name":{$regex:search,$options:'i'})
I am getting an empty array as output, as I mentioned multiple fields together in .find()..
I am getting output if I use the below code(i.e) find only one field..
const Rest = await Restaurant.find({name:{$regex:search,$options:"i"}})
If I search for any of the 3 fields name/locality/cuisine.name I should get appropriate output.
Your original query was incorrect. Those conditions should be grouped into one parameter. It should be as below:
const Rest = await Restaurant.find({
name: {
$regex: search,
$options: "i"
},
locality: {
$regex: search,
$options: "i"
},
"cuisine.name": {
$regex: search,
$options: "i"
}
})
The above query will work the matching in AND conditions (all filter criteria must be fulfilled).
Instead, you need to work the query in OR conditions with the $or operator (either one of the filter criteria needed to be fulfilled).
Solution
const Rest = await Restaurant.find({
$or: [
{
name: {
$regex: search,
$options: "i"
}
},
{
locality: {
$regex: search,
$options: "i"
}
},
{
"cuisine.name": {
$regex: search,
$options: "i"
}
}
]
})
Demo # Mongo Playground
You can look at $and operator and $or operator in Mongodb, You can use $and operator if you want to match all of the given parameters or $or operator if one must match. Like this:
const Rest = await Restaurant.find({
$and: [
{ name: { $regex: search, $options: "i" } },
{ locality: { $regex: search, $options: "i" } },
{ "cuisine.name": { $regex: search, $options: "i" } },
],
});
See the documentation:
$and operator
$or operator

monogdb full text search, ignore characters

Im implementing a mongodb search.
The search performs a find on field values:
[{
value: "my.string.here"
}, {
value: "my other here"
}{
...
}]
When i enter "my" both entries are found. What have my query to look like to ignore the dots on the first entry? So when i enter "my string" the first element gets returned?
Actually it works only when i enter "my.string" which is not nice.
let limit = Number(req.query.limit || 100);
let skip = Number(req.query.skip || 0);
collection.find({
$or: [{
value: new RegExp(req.body.search, "gi")
}, {
tags: {
$in: req.body.search.split(",").map((val) => {
return new RegExp(val, "gi")
})
}
}]
}).skip(skip).limit(limit).toArray((err, result) => {
if (err) {
res.status(500).json(err);
} else {
res.status(200).json(result);
}
});
EDIT:
A solution could look like this:
let query = {
$or: [{
name: new RegExp(req.body.search, "gi")
}, {
tags: {
$in: req.body.search.split(",").map((val) => {
return new RegExp(val, "gi")
})
}
}, {
name: new RegExp(req.body.search.split(' ').join('.'), "gi")
}, {
name: new RegExp(req.body.search.split(' ').join('_'), "gi")
}, {
name: new RegExp(req.body.search.split(' ').join('-'), "gi")
}]
};
But i find it ugly and not elegant. Is there a better way to do this ?

$regex to find whole words, mongodb

Find items containing a whole word.
const queryparam = 'microsoft';
mongoose.model('tag').find({name: { $regex: new RegExp("\w"+queryparam+"\w" ), '$options': 'i' }});
// tag collection
[
{
name: 'Microsoft word" // this should be returned by query
},
{
name: 'Microsoft-word" // this should not be returned by query
}
]
It's not working.
Try this (thanks to #Toto):
db.tag.find({
name: {
"$regex": "\\bMicrosoft\\b\\s",
"$options": "i"
}
})
MongoPlayground

Unable to use $regex in mongoose in aggregation query?

I am getting an error while using $regex in mongoose aggregation query . I am getting an invalid operator with error no 15999 . Please help guys.
{ $match: { "_id": ObjectId(req.headers.token) } }, {
$project: {
inventory: {
$filter: {
input: '$inventory',
as: 'inventory',
cond: {$or:[{"$$inventory.item":new RegExp('^'+req.query.text+'$', "i")},{"$$inventory.sku":new RegExp('^'+req.query.text+'$', "i")}]}
}
},
_id: 0
}
}
You can use regex in $match and you will get your result as in this example
Pincodes.aggregate([
{ "$match": { "district": new RegExp('^' + req.query.district, "i") }
},
{ "$group": { "_id": "$district" } }])
.exec((err, data) => {
if (err) {
res.status(500).json({
data: err
})
}
else {
res.status(200).json({
data: data
})
}
})
Doing just agg.match({'<fieldName'>:new RegExp('^' + req.query.district, "i")}) didnt work for me
I had to use eval in the solution.
if you are JSON.stringifying the aggregate query to see the output you won't see the effect of eval. Eval will have an effect later on when passed down to mongo.
agg.match({'<fieldName'>:eval(new RegExp('^' + req.query.district, "i"))});

MongoDB search by tags with regular expression

Suppose I have model looks like:
{_id: ..., tags: ["stackoverflow", "github", "bootstrap", ...]}
How can I search for all items that match BOTH /stack/ and /git/ ?
There mongo regex doc
http://docs.mongodb.org/manual/reference/operator/query/regex/
db.collection.find(
{
$and :
[
{ tags: { $regex: /git/ } },
{ tags: { $regex: /boot/ } }
]
})
this solution may help you
Searching in MongoDB
Just thought this question/previous answer can be improved:
The first solution that comes to mind when approaching this problem is :
db.collection.find({ tags: { $regex: /git/ }, tags: { $regex: /stack/ }}
But this will result in finding tag items which match only 'stack', because mongo builds this query in way which results in the first criteria overridden by second criteria(as they have the same key 'tag').
Hence the correct solution would be :
db.collection.find(
{
$and :
[
{ tags: { $regex: /git/ } },
{ tags: { $regex: /stack/ } }
]
})
Which will find documents which match both the regex conditions 'git' and 'stack' although the syntax is a bit contrived.