node.js - sending regex to server - regex

I've created a client side mongodb interface to talk to server side mongodb.
it's very similar to the mini-mongo implemented in the meteor.
here is an example:
model.find({"field": /search/}).exec(function(err, model){
construct(model);
});
now normally everything works fine except when I use the regex.
and I know what's the problem but I cannot fix it.
the problem, as you have guessed it, is when the regex /regexParameter/ when sent by ajax to server, is converted to "/regexParameter/" and the single quotes(or double) make the regex a normal string.
in the server I have something like this:
var findObject = req.query.findObject // {"field": "/search/"} :(
req.models[config.table]
.find(findObject)
.exec(function(err, model){
return res.json({
error: err,
result: model,
});
});
is there anything I can do to make this work without writing like 100 of lines of code that iterates through each of the findObject and matches every string for a regex...?
Thanks everyone

You are right - you cannot pass RegExp objects between client and server because during serialization they are converted to strings.
Solution? (or perhaps - a workaround)
Use $regex operator in your queries, so you don't need to use RegExp objects.
So this:
{
field: /search/
}
Becomes this:
{
field: {
$regex: 'search'
}
}
Or, giving a case-insensitive search example:
{
field: {
$regex: 'search',
$options: 'i'
}
}
(instead of field: /search/i)
Read more about $regex syntax here (including about some of its restrictions).

Related

Mongo query syntax error

I don't understand why one of these syntaxs work and the other one doesn't. It's my understanding that they both pretty much mean the same.
This works
{ 'profile.fname' : { $regex: ".*" + this.queryParams.value + ".*", $options: '-i'}},
This does not work
{ profile : { fname : { $regex: ".*" + this.queryParams.value + ".*", $options: '-i'}}},
Example data structure looks like:
{
"_id":"ybhng3YCu4W4MSzz9",
"createdAt":"2016-08-23T10:44:33.088Z",
"emails":[{"address":"xy#z.co.uk","verified":false}],
"profile":
{
"fname":"name",
"lname":"otherName"
},
"roles":["admin"]
}
The first one produces the correct result but the second one produces nothing - as in an empty array. From debugging I know this must be the wrong syntax somewhere but I cannot see it.
I am using meteor as the server side.
If you are querying against an embedded document, you need to use dot notation like you're doing in your first query.
If you supply it a document, it must be an exact match. In this case you'd literally need:
{ profile: { fname: "name", lname :"otherName"} }
Of course this looks like bad design to me; why is profile an embedded document in the first place? Instead of something like this:
{
"_id":"ybhng3YCu4W4MSzz9",
"createdAt":"2016-08-23T10:44:33.088Z",
"emails":[{"address":"xy#z.co.uk","verified":false}],
"fname":"name",
"lname":"otherName"
"roles":["admin"]
}
Reference: Query on Embedded Documents

mongoose count() function with regex case insensitive matching sub string also

I am trying to find out a simple solution to handle case sensitive email using regex, so far it works good when inserting/querying the document using Mongoose but when I'm validating if the user exists using the Model.count method, its not working as expected.
I have defined this static function in the schema, which takes the username and return the count of occurance in the collection.
userSchema.statics.exist = function(username, cb){
this.count({ "username": new RegExp(username, "i") }, cb);
};
and I have a controller function which calls this static like this:
userExist: function (req, res) {
UserModel.exist(req.body.username, function (err, count) {
res.json({exist: count});
});
}
if I pass user#example.com in the req.body.username field ( where user#example.com exist in the database), it returns 1
but its returning 1 even if I enter I enter user#examp or user#exampl or user#example.c
Not sure what I'm doing wrong, I thought it may be issue with regex, so I tested this regex for validity:
var username = "user#example.com";
var pattern = new RegExp(username, "i");
pattern.match("user#examp"); // this returns false
Any help is appreciated. Thanks !
I was able to solve this issue by changing the regex a little bit like this:
userSchema.statics.exist = function(username, cb){
this.count({ "username": new RegExp('^'+username+'$', 'i') }, cb);
};
Hope this helps someone. Any other suggestions are welcome

mongo shell search for value like "/"fubak#drooop.com"/"

I may have let a bug loose on our code that essentially ruined some of our db data.
Every now and again we come across a username that has " " in his email so we need to fix this.
How can I search for a value like "/"fubak#drooop.com"/" in one field using my mongo shell?
I have been trying all the combinations I can think of like:
db.users.find(username: /"/" .* /)
and
db.users.find(username: //.*//)
or
db.users.find(username: /"".*/)
But nothing seems to work.
new RegExp('^".*')
This finds all the records that start with ".
Thanks.
Try this:
db.users.find({ email: "(?:[^\\"]+|\\.)* })
This will match all documents which contains quotes in the email
Not to sure which one is you problem, so the solutions to both possible scenarios with data in MongoDB like this:
{ "email" : "\"/\"fubak#drooop.com\"/\"" }
{ "email" : "/fubak#drooop.com/" }
{ "email": "\"blablabla#blip.ca\"" }
First document match:
db.problem.find({ email: /^\"/ })
Second document match:
db.problem.find({ email: /^\// })
Third document match
db.problem.find({ email: /^\"/ })
Do not know what you mean otherwise by "having quotes" as that is not valid JSON and by extension is also invalid BSON.

Express.JS regular expression for example.com/:username

// ex: http://example.com/john_smith
app.get('/^(a-z)_(0-9)', function(req, res) {
res.send('user');
});
// ex: http://example.com/john_smith/messages/1987234
app.get('/^(a-z)_(0-9)/messages/:id', function(req, res) {
res.send('message');
});
I wrote the above code for an app that I want to pass a username as a url variable to node.js like I would do: $username = $_GET['username']; in PHP. I'm not too good at writing regular expressions so I wanted to see if anyone could set me on the right track. Thanks in advance.
From your requirement it doesn't seem like you need a regular expression. Just use a a variable in your rule, like below:
// Grabs whatever comes after /user/ and maps it to req.params.id
app.get('/user/:id', function (req, res) {
var userId = req.params.id;
res.send(userId);
});
If you want to have better control, you could use a regular expression. To grab things you are interested in from the expression, use a capture group (which are typically expressed as a set of matching parenthesis):
// Grabs the lowercase string coming after /user/ and maps it to req.params[0]
app.get(/^\/user\/([a-z]+)$/, function (req, res) {
var userId = req.params[0];
res.send(userId);
});
A little off topic, but here's a really good intro to express.js that will help you understand it better (including how the routes work):
http://evanhahn.com/understanding-express-js/
You're looking for req.params, which is an array of all of the capture groups in the regex.
The capture groups start at 1; req.params[0] is the entire match.

'like' or $regex query inside $cond in MongoDB

Please go through this question of mine:
MongoDB $group and explicit group formation with computed column
But this time, I need to compare strings, not numbers.The CASE query must have a LIKE:
CASE WHEN source LIKE '%Web%' THEN 'Web'
I then need to group by source. How to write this in Mongo? I am trying the following but not sure if $regex is supported inside $cond. By the way, is there a list of valid operators inside $cond somewhere? Looks like $cond isn't very fond of me :)
db.Twitter.aggregate(
{ $project: {
"_id":0,
"Source": {
$cond: [
{ $regex:['$source','/.* Android.*/'] },
'Android',
{ $cond: [
{ $eq: ['$source', 'web'] }, 'Web', 'Others'
] }
]
}
} }
);
There're many other values that I need to write in there, doing a deeper nesting. This is just an example with just 'Android' and 'Web' for the sake of brevity. I have tried both with $eq and $regex. Using $regex gives error of invalid operator whereas using $eq doesn't understand the regex expression and puts everything under 'Others'. If this is possible with regex, kindly let me know how to write it for case-insensitive match.
Thanks for any help :-)
Well, it still seems to be not even scheduled to be implemented :(
https://jira.mongodb.org/browse/SERVER-8892
I'm using 2.6 and took a peek on 3.0, but it's just not there.
There's one workaround though, if you can project your problem onto a stable substring. Then you can $substr the field and use multiple nested $cond. It's awkward, but it works.
Maybe you can try it with MapReduce.
var map = function()
{
var reg1=new RegExp("(Android)+");
var reg2=new RegExp("(web)+");
if (reg1.test(this.source)){
emit(this._id,'Android');
}
else if (reg2.test(this.source))
{
emit(this._id,'web');
}
}
var reduce = function (key,value){
var reduced = {
id:key,
source:value
}
return reduced;
}
db.Twitter.mapReduce(map,reduce,{out:'map_reduce_result'});
db.map_reduce_result.find();
You can use JavaScript regular expresions instead of MongoDB $regex.