How to find matches that occur within a specified string with regex? - regex

I have a unique situation where I need to query a mongo database to find the names of people who occur in a body of text. The query must specify the body of text and find records with values that occur in the body of text. How can I do this with a regular expression?
I need to write a query where this would match:
/Jonathan is a handsome guy/.test('Jonathan')
The problem is that the text inside "test" is the value of a mongo field, so this query must be written such that the body of text is provided as input, and it matches on names that occur within (are substrings of) the body of text.
A more concrete example:
db.test.find();
{ "_id" : ObjectId("547e9b79f2b519cd1657b21e"), "name" : "Jonathan" }
{ "_id" : ObjectId("547e9b88f2b519cd1657b21f"), "name" : "Sandy" }
db.test.find({name: { $in: [/Jonathan has the best queries/]} } );
I need to construct a query that would return "Jonathan" when provided the input "Jonathan has the best queries"

This $where may do the trick, though can be very slow:
db.test.find({$where: function() {
var mystr = '/Jonathan has the best queries/';
var patt = new RegExp(this.name);
if (patt.test(mystr)) return true;
return false;
}})

Related

Regex to match sub string of a string

I need to construct a regular expression to match a given value to the brand field of my product array. For instance, given the parameter "am", an array of the following products would be returned: [Amana, Mama, etc]. How do I complete this function?
public searchProduct(term) {
this.products.forEach(product => {
if (product.brand.match(`${term}`)) {
console.log('mtch found', product.brand)
}
});
return of(this.products)
}
Unless you have some special reasons to use regex, you can use filter and includes to return only items of your array containing your substring
public searchProduct(term) {
return this.products.filter(x => x.brand.includes(term))
}

How to Set Multple Regex Costraints on textbox in ZKOSS

I have a textbox which should only accept Characters:-for that first regex has been set in constraint and it should not accept some reserved keywords that are A,R,F,U .Since two different constraints are set ,i want user to see the specific message ,for first it should be Illegal Value i.e default zkoss error and when he/she enters a reserved character ,it should show that reserved code has been put.
But somehow the following code doesnt work :
field_code.setConstraint("/[a-zA-Z]/ : {Illegal Value} ,/[^AaRrUuFf]/ : Reserved Code");
The output is the first regex works fine but on offending the same " {Illegal Value} ,/[^AaRrUuFf]/ : Reserved Code" is displayed as error.
You can't do it in the zul, but with help of a SimpleConstraint you could create this.
Create your own class, and extend SimpleConstraint.
Then hold 2 Matcher vars for each constraint.
At last, override the Validate method to something like this :
#Override
public void validate(Component comp, Object value) {
if (value != null && value instanceof String) {
String stringValue = (String) value;
if (!expression1.reset(stringValue).matches()) {
throw new WrongValueException(comp, errorMsg1);
}
if (!expression2.reset(stringValue).matches()) {
throw new WrongValueException(comp,errorMsg2);
}
} else {
// do what needs to be done when value is null or not a String.
}
}

Replacing Pattern Matches in a String kept as value of a key in JSON

I have a JSON file that has a key value pairs as shown below
{
"parameters": "<FieldLabel Type='Something'><Label><![CDATA[Click on this number to initiate call <a href='tel:123456' parameter='DialMe,100.200.3000'>100.200.3000'>100.200.3000'>100.200.3000'>tel:1002003000'>100.200.3000</a> or<a href='tel:911'parameter='dial911,911'>911'>911'>911'>tel:911'>911</a> ]]></Label><Description><![CDATA[]]></Description></FieldLabel>"
}
I want to replace
parameter='DialMe,100.200.3000' with my-url-click='DialMe,null,null,100.200.3000'
and
parameter='dial911,911' with my-url-click='dial911,null,null,911'
before I can render it on as HTML using Angular's ng-bind-html and $sce.trustAsHtml.
The catch is the JSON has many such key value pairs and each of them has different values for the parameter like parameter=dial108,108.So normal string replacement is not possible.How shall I do it for each of them?
Try this:
var str = "<FieldLabel Type='Something'><Label><![CDATA[Click on this number to initiate call <a href='tel:123456' parameter='DialMe,100.200.3000'>100.200.3000'>100.200.3000'>100.200.3000'>tel:1002003000'>100.200.3000</a> or<a href='tel:911'parameter='dial911,911'>911'>911'>911'>tel:911'>911</a> ]]></Label><Description><![CDATA[]]></Description></FieldLabel>";
str = str.replace(/parameter=\'.*,/g, function(s){
return s.replace("parameter", "my-url-click") + "null,null,"
});

How to combine multiple criteria in OR query dynamically in Play Morphia

I am trying to use a kind of builder pattern to build an OR query using multiple criteria depending upon the scenario. An example is
public class Stylist extends Model {
public String firstName;
public String lastName;
public String status;
...
}
I would like to search Stylist collection if the first name or last name matches a given string and also status matches another string. I am writing the query as follows:
MorphiaQuery query = Stylist.q();
if (some condition) {
query.or(query.criteria("status").equal("PendingApproval"), query.criteria("status").equal(EntityStatus.ACTIVE));
}
if (some other condition as well) {
query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
}
When both the conditions are met, I see that query contains only the criteria related to firstName and lastName i.e. different OR criteria are not added/appended but overwritten. It's quite different from filter criteria where all the different filter conditions are appended and you can easily build queries containing multiple AND conditions.
I can solve the problem by putting my conditions differently and building my queries differently but doesn't seem to be an elegant way. Am I doing something wrong ?
I am using Play! Framework 1.2.4 and Play Morphia module version 1.2.5a
Update
To put it more clearly, I would like to AND multiple OR queries. Concretely, in the above mentioned scenario, I would like to
I would like to search for Stylists where :
firstName or lastName contains supplied name AND
status equals ACTIVE or PENDING_APPROVAL.
I have been able to construct the query directly on Mongo shell through :
db.stylists.find({$and: [{$or : [{status: "PENDING_APPROVAL"}, {status : "ACTIVE"}]},{$or : [{firstName : { "$regex" : "test" , "$options" : "i"}}, {lastName : { "$regex" : "test" , "$options" : "i"}}]}] }).pretty();
But have not able to achieve the same through Query API methods. Here is my attempt :
Query<Stylist> query = MorphiaPlugin.ds().find(Stylist.class);
CriteriaContainer or3 = query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
CriteriaContainer or4 = query.or(query.criteria("status").equal("PENDING_APPROVAL"), query.criteria("status").equal("ACTIVE"));
query.and(or3, or4);
query.toString() results in following output : { "$or" : [ { "status" : "PENDING_APPROVAL"} , { "status" : "ACTIVE"}]}
Not sure, where am I missing ?
I guess there could be 2 ways to handle your case:
first, use List<Criteria>
MorphiaQuery query = Stylist.q();
List<Criteria> l = new ArrayList<Criteria>()
if (some condition) {
l.add(query.criteria("status").equals("PendingApproval");
l.add(query.criteria("status").equal(EntityStatus.ACTIVE));
}
if (some other conditional as well) {
l.add(query.criteria("firstName").containsIgnoreCase(name));
l.add(query.criteria("lastName").containsIgnoreCase(name));
}
query.or(l.toArray());
Second, use CritieriaContainer
MorphiaQuery query = Stylist.q();
CriteriaContainer cc = null;
if (some condition) {
cc = query.or(query.criteria("status").equal("PendingApproval"), query.criteria("status").equal(EntityStatus.ACTIVE));
}
if (some other condition) {
if (null != cc) query.or(cc, query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
else query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
}

Mongodb - regex match of keys for subdocuments

I have some documents saved in a collection (called urls) that look like this:
{
payload:{
url_google.com:{
url:'google.com',
text:'search'
}
}
},
{
payload:{
url_t.co:{
url:'t.co',
text:'url shortener'
}
}
},
{
payload:{
url_facebook.com:{
url:'facebook.com',
text:'social network'
}
}
}
Using the mongo CLI, is it possible to look for subdocuments of payload that match /^url_/? And, if that's possible, would it also be possible to query on the match's subdocuments (for example, make sure text exists)?
I was thinking something like this:
db.urls.find({"payload":{"$regex":/^url_/}}).count();
But that's returning 0 results.
Any help or suggestions would be great.
Thanks,
Matt
It's not possible to query against document keys in this way. You can search for exact matches using $exists, but you cannot find key names that match a pattern.
I assume (perhaps incorrectly) that you're trying to find documents which have a URL sub-document, and that not all documents will have this? Why not push that type information down a level, something like:
{
payload: {
type: "url",
url: "Facebook.com",
...
}
}
Then you could query like:
db.foo.find({"payload.type": "url", ...})
I would also be remiss if I did not note that you shouldn't use dots (.) is key names in MongoDB. In some cases it's possible to create documents like this, but it will cause great confusions as you attempt to query into embedded documents (where Mongo uses dot as a "path separator" so to speak).
You can do it but you need to use aggregation: Aggregation is pipeline where each stage is applied to each document. You have a wide range of stages to perform various tasks.
I wrote an aggregate pipeline for this specific problem. If you don't need the count but the documents itself you might want to have a look at the $replaceRoot stage.
EDIT: This works only from Mongo v3.4.4 onwards (thanks for the hint #hwase0ng)
db.getCollection('urls').aggregate([
{
// creating a nested array with keys and values
// of the payload subdocument.
// all other fields of the original document
// are removed and only the filed arrayofkeyvalue persists
"$project": {
"arrayofkeyvalue": {
"$objectToArray": "$$ROOT.payload"
}
}
},
{
"$project": {
// extract only the keys of the array
"urlKeys": "$arrayofkeyvalue.k"
}
},
{
// merge all documents
"$group": {
// _id is mandatory and can be set
// in our case to any value
"_id": 1,
// create one big (unfortunately double
// nested) array with the keys
"urls": {
"$push": "$urlKeys"
}
}
},
{
// "explode" the array and create
// one document for each entry
"$unwind": "$urls"
},
{
// "explode" again as the arry
// is nested twice ...
"$unwind": "$urls"
},
{
// now "query" the documents
// with your regex
"$match": {
"urls": {
"$regex": /url_/
}
}
},
{
// finally count the number of
// matched documents
"$count": "count"
}
])