Node.js and Mongoose regex query on multiple fields - regex

I would like to query multiple fields using the same regular expression for both. In this query, I would like to accept a single text input and check both the firstName and lastName fields for results. I can query a single field just fine using the regex function in the mongoose documentation, but the syntax for an 'or' clause is giving me trouble.
var re = new RegExp(req.params.search, 'i');
app.User.find().or([{ 'firstName': { $regex: re }}, { 'lastName': { $regex: re }}]).sort('title', 1).exec(function(err, users) {
res.json(JSON.stringify(users));
});
(I'm running mongoose 2.7.1 on node.js 0.6.12)

The code above works fine for a query on multiple fields. Turns out I had some bad data.

My solution is to use $function that allows you to concatenate multiple fields and match their combined value against your regular expression.
const { search } = req.params;
var regex = new RegExp(`.*${search}.*`, 'i');
app.User.find({
$expr: {
$function: {
body: `function(firstName, lastName) { return (firstName+' '+lastName).match(${regex}) }`,
args: ['$firstName', '$lastName'],
lang: "js"
}
}
})
.exec((err, users) => {
res.json(JSON.stringify(users));
});

Related

loopback model.find based on param from related model

I have a problem with falowing situation:
Model 1: Guest - props {"slug":"string"}
Model 2: Project - props {"prefix":"string"}
Relation: Project has many guests
How to write remote method: findGuestWithProject(prefix, slug) that will return guest with slug (exact match but case insensitive) and related project with exact prefix?
Problems I encountered:
Initial filter return Guests with similar but not exact slug f.e. if I pass "anna" .find could return guests with slug "anna-maria", so later on I need to check id slug is exactly the same.
Initial filter return Guests with different project.prefix so I need to do extra loop to find exact match.
I need to count iteration to return callback if not match found.
Guest.getGuestProject = function(prefix, slug, cb) {
if (!prefix) return;
var pattern = new RegExp(slug, "i");
app.models.Project.findOne({
"where": {"prefix": prefix}
},(err, project) => {
if (err) { throw err};
if (!project) cb(null, null);
return project.guests({
"where": {"slug": pattern },
"include": {"relation": "project", "scope": {"include": {"relation": "rsvps"}}}
}, (err, guests) => {
if (guests.length === 0) cb(null, null)
guests.forEach(guest => {
if (guest.slug.toLowerCase() === slug.toLowerCase()) {
cb(null, guest)
}
})
})
})
Regarding 1: Your regexp is checking for anything containing slug
For 2 and 3 I've just rewritten it. You haven't specified what db connector you are using (mongodb, mysql, postgres, etc) so I've written this example based on Postgresql, which is the one I usually use and one of the worst-case-scenarios, given that relational databases don't support filtering by nested properties. If you are using either Mongodb or Cloudant take a look at the example provided in https://loopback.io/doc/en/lb3/Querying-data.html#filtering-nested-properties because this snippet could be simpler.
If this answer is not what you were looking for then I'll probably need more details. I'm also using promises instead of callbacks.
Guest.getGuestProject = function(prefix, slug) {
const Project = Guest.app.models.Project;
// First of all find projects with the given prefix
return Project.find({
where: {
prefix: prefix
},
include: 'guests'
}).then(projects => {
projects.forEach(project => {
let guests = project.guests();
guests.forEach(guest => {
// See if guest.slug matches (case-insensitive)
if (guest.slug.match(new RegExp(slug, 'i'))) {
return guest;
}
});
});
});
};

How to query mongo db to return all combinations of keys in a search term?

In the mongo db are tags. I'm trying to pull out all the tags that would match starting from the beginning of a search term. Is it possible to achieve the following in a mongo query?
Mongo data:
[
{ tag: '123' },
{ tag: '1234' },
{ tag: '123456' },
{ tag: '987' },
{ tag: '555' }
]
Query search term = '12349339'
Result desired:
[
{ tag: '123'},
{ tag: '1234' }
]
or
[
{ tag: '1234' }
]
I've tried regex expressions to no avail as using (^) would only be useful if the longer search term was in the db and I was searching using a substring.
Update: Here's my regex attempt for anyone trying this approach.
tags.find({tag: {$regex: '^12349339*'}})
Returns nothing. If I wanted all tags that match '123' then this kind of query would work.
tags.find({tag: {$regex: '^123'}})
Returns:
[
{ tag: '123' },
{ tag: '1234' },
{ tag: '123456' }
]
But I wanted the reverse. So, figured I needed an aggregate function or something.
You could do:
{
$where: "'12349339'.indexOf(this.tag) == 0"
}
Obligatory performance note on using $where: The $where provides greater flexibility, but requires that the database processes the JavaScript expression or function for each document in the collection.
https://docs.mongodb.com/manual/reference/operator/query/where/

.pluck function in strongloop loopback?

Does storongloop loopback has pluck function for a given model ?
For a Product model,
in Rails I can write
Product.where(some_condition).pluck(:name)
It will return an array of names of products matching the condition.
Is there anything similar in loopback?
PS: I know I can use fields filter and then use underscore( or lodash)'s pluck but that's a two step process.
Select specific columns:
{"fields":{"name":true, "email":true}}
Where condition:
{"where":{"id":2}}
Combining:
{"fields":{"id":true},"where":{"id":{"inq":[10,20,30]}}}
The above code works in swagger. Node.js code would be as follows:
var m = server.models.customer;
m.findOne({
fields: ['name', 'email'],
where: {
id:{inq:[10,20,30]}}
}
}, function (err, data) {
console.log(data);
})

Convert plain text email to clickable link - REGEX/jQuery

I am trying to convert plain text email addresses into clickable mailto links inside of a table.
I have the following function that is converting found links into mailto links, but it only seems to work for the first found link. Any subsequent links (2nd, 3rd occurrence etc.) remain as plain text links. I can't seem to figure out what I might be doing wrong. Any help would be much appreciated!
The code:
HTML
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<div class='filter-email-box'>
<div>This is a sample text which contains john#gmail.com </div>
<div>This text contains two emails adam#example.com and paul#example.com </div>
</div>
Javascript
$(".filter-email-box div").filter(function(){
var html = $(this).html();
var emailPattern = /[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/;
var matched_str = $(this).html().match(emailPattern);
if(matched_str){
$(this).html(html.replace(emailPattern,"<a href='mailto:"+matched_str+"'>"+matched_str+"</a>"));
return $(this)
}
})
Heres the fiddle I've setup:
http://jsfiddle.net/z6LF5/
When there's more than one email address, JQuery method match returns an array (when the global search flag g is set), so we're looping over that array (called matched_str in this case) and replacing the matching emails.
$(".filter-email-box div").filter(function () {
var html = $(this).html();
var emailPattern = /[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/g;
var matched_str = $(this).html().match(emailPattern);
if ( matched_str ) {
var text = $(this).html();
$.each(matched_str, function (index, value) {
text = text.replace(value,"<a href='mailto:"+value+"'>"+value+"</a>");
});
$(this).html(text);
return $(this)
}
})
JSFiddle
Use the g (global) modifier which ( finds all matches rather than stopping after the first match ).
You could implement the following:
$('.filter-email-box div').ready(function() {
$('.filter-email-box div').each(function() {
var html = $(this).html();
var regex = /([a-z0-9._-]+#[a-z0-9.-]+\.[a-z]{2,4})/ig
var text = html.replace(regex, "<a href='mailto:$1'>$1</a>");
$(this).html(text);
});
});
Fiddle
if anyone is interested I translated the jquery code to vanilla JS code
var elem = document.querySelector('.filter-email-box');
var html = elem.innerHTML;
if (html) {
var regex = /([a-z0-9._-]+#[a-z0-9.-]+\.[a-z]{2,4})/ig;
elem.innerHTML = html.replace(regex, '$1');
}
Demo link: https://jsfiddle.net/q0x4tjr3/

mongodb regex searching issue in meteor

my code is
var search_element=Session.get("search_string");
var adc="/"+search_element+"*/";
console.log(adc);
return Polls_Coll.find({question:{$regex:adc}});
Why it is not working
if i give
Polls_Coll.find({question:{$regex:/Best*/}});
in conslow it's working and if i substitute the regex with the value(search_element) it is not working. I think it is replacing like this
Polls_Coll.find({question:{$regex:"/Best*/"}});(with quotes "/Best*/")
Is that the main problem? or Is there any silly mistake i did??
There are two types of syntax:
Polls_Coll.find({question:/Best*/});
and
Polls_Coll.find({question:{$regex:"Best*"}});
You've used elements in each so thats probably why its not working. There's a bit more details about this at the mongodb docs: http://docs.mongodb.org/manual/reference/operator/query/regex/
Both forms work fine in Meteor, so you shouldn't have a problem with them.
I use this syntax and it's work for me:
Polls_Coll.find({ name: {$regex: "adc", $options: '-i'} });
It similar with:
SELECT * FROM Polls_Coll WHERE name LIKE '%adc%'
I also use https://atmospherejs.com/meteor/reactive-var with implementation like code below:
if (Meteor.isServer) {
Meteor.publish('customersSearch', function(searchValue){
if (searchValue) {
return Customers.find({ name: {$regex: searchValue, $options: '-i'} });
}
});
}
var searchQuery = new ReactiveVar();
Template.NewRO.onCreated(function(){
var self = this;
self.autorun(function() {
self.subscribe('vehicles');
self.subscribe('customersSearch', searchQuery.get());
});
});