$regex to find a document in mongodb that contains a string - regex

I am working on a db query in mongo where i need to query the document by regular expressing the string field(fieldToQuery).
the datastructure is like
{
fieldToQuery : "4052577300",
someOtherField : "some value",
...
...
}
I have the value like "804052577300", using which i have to query the above document.
How to achieve the same using $regex operator?
Update:
I need to do like ends with regex in mongo.

You could do a sort of reverse regex query where you create a regex using the fieldToQuery value and then test that against your query value:
var value = "804052577300";
db.test.find({
$where: "new RegExp(this.fieldToQuery + '$').test('" + value + "');"
});
The $where operator allows you to execute arbitrary JavaScript against each doc in your collection; where this is the current doc, and the truthy result of the expression determines whether the doc should be included in the result set.
So in this case, a new RegExp is built for each doc's fieldToQuery field with a $ at the end to anchor the search to the end of the string. The test method of the regex is then called to test whether the value string matches the regex.
The $where string is evaluated server-side, so value's value must be evaluated client-side by directly including its value into the $where string.
Note that $where queries can be quite slow as they can't use indexes.

You could do something like this:
db.collection.find({ fieldToQuery: /4052577300$/})
The regex pattern above is equivalent to the SQL's LIKE operation:
select * from table where fieldToQuery like '%4052577300' => will return the document with the value "804052577300"

Related

Query to fetch data for list of regular expressions given

I have to fetch data for given list of regular expressions. for single regular expression below query is working but for list i am facing issue
select id from res r where
(?1 is null or CAST(r.value AS TEXT) ~ cast(?1 as TEXT));
?1 is [^\d{3}\d{1,}133\d{1,}$] and it is working fine
Now when i put list of regular expressions then [^\d{3}\d{1,}133\d{1,}$, 75$] it is not working
If ?1 type is text array (text[]) or a valid textual representation of text array syntax then
select id from res r where
?1 is null
or exists (select from unnest(?1::text[]) rx where r.value::text ~ rx);
Please note that the syntax of the text array of regular expressions shall not be
[^\d{3}\d{1,}133\d{1,}$, 75$] but {"^\\d{3}\\d{1,}133\\d{1,}$", 75$}
Edit
It might be a good idea to define a function that returns true if the first argument matches any of the regular expressions in an array. Something similar to a non-existent but good to have REGEX_IN operator.
create or replace function regex_any(needle text, haystack_rules text[])
returns boolean language sql immutable as $$
select exists (select from unnest(haystack_rules) haystack_rule where needle ~ haystack_rule);
$$;
Then your query will look like this:
select id from res r
where ?1 is null
or regex_any(r.value::text, ?1);
From the documentation, the ~ operator works against a single regular expression. You would need to update your query to work against a list of regular expressions. For example,
select id from res r where
(?1 is null or (select bool_and(r.value::text ~ x.exp) FROM unnest(?1)))
The second part of the where returns true if the column matches all regular expressions in ?1. Depending on the size of your input, you can extract unnest(?1) into a CTE.

php doctrine createQueryBuilder special character

Database store the value "&You" but the query below doesn't return result
$buildQuery = $this->createQueryBuilder('r')
->where('r.TitreSearch LIKE :term')
->setParameter('term', "%&You%")
;
On the other hand if I search "You" I have a result
why doctrine not understand character "&" ?
The problem is not the ampersand character but the query itself.
If you want LIKE to match a pattern within the column value, you must enclose the search term with percentage signs (i.e. %term%). Without the percentage signs, LIKE acts just the same as the = operator; it looks for an exact match.
Try the following:
$term = "&You";
$buildQuery = $this->createQueryBuilder('r')
->where('r.TitreSearch LIKE :term')
->setParameter('term', "%$term%");

Is there a database that can store regex as values?

I am looking for a database that can store regex expressions as values. E.g. somthing like this:
{:name => "Tim", :count => 3, :expression => /t+/},
{:name => "Rob", :count => 4, :expression => /a\d+/},
{:name => "Fil", :count => 1, :expression => /tt/},
{:name => "Marc", :count => 1, :expression => /bb/}
So I could return rows/documents based on whether the query matches the expression or not (e.g."FIND rows WHERE "tt" =~ :expression"). And get Tim and Fil rows as the result. Most databases can do the exactly opposite thing (check whether a text field matches a regex query). But neither mongo nor postgres can do the opposite thing, unfortunately.
P.S. Or perhaps I am wrong and there are some extensions for postgres or mongo that allow me to store regex?
MongoDB will allow you to store actual regular expressions (i.e. not a string representing a regular expression), as shown below:
> db.mycoll.insertOne({myregex: /aa/})
{
"acknowledged" : true,
"insertedId" : ObjectId("5826414249bf0898c1059b38")
}
> db.mycoll.insertOne({myregex: /a+/})
{
"acknowledged" : true,
"insertedId" : ObjectId("5826414949bf0898c1059b39")
}
> db.mycoll.find()
{ "_id" : ObjectId("5826414249bf0898c1059b38"), "myregex" : /aa/ }
{ "_id" : ObjectId("5826414949bf0898c1059b39"), "myregex" : /a+/ }
You can use this to then query for rows with a regex that matches a query, as follows:
> db.mycoll.find(function() { return this.myregex.test('a'); } )
{ "_id" : ObjectId("5826414949bf0898c1059b39"), "myregex" : /a+/ }
Here we search for rows where the string 'a' is matched by the myregex field, resulting in the second document, with regex /a+/, being returned.
Oracle database can do that.
Example query: WHERE REGEXP_LIKE(first_name, '^Ste(v|ph)en$')
You want to select an regexp from a column, See SQL Fiddle example below for an example.
SQL Fiddle
Choose Oracle database.
In schema window execute the following:
CREATE TABLE regexp (name VARCHAR2(20), count NUMBER, regexp VARCHAR2(50));
INSERT INTO regexp VALUES ('Tim', 3, 't+');
INSERT INTO regexp VALUES ('Rob', 4, 'a\d+');
INSERT INTO regexp VALUES ('Fil', 1, 'tt');
INSERT INTO regexp VALUES ('Marc', 1, 'bb');
COMMIT;
Execute an SQL statement, e.g. (as you mentioned in your question):
SELECT * FROM regexp WHERE REGEXP_LIKE('tt', regexp);
Yields:
NAME COUNT REGEXP
Tim 3 t+
Fil 1 tt
Reference here.
Excerpt:
Oracle Database implements regular expression support with a set of
Oracle Database SQL functions and conditions that enable you to search
and manipulate string data. You can use these functions in any
environment that supports Oracle Database SQL. You can use these
functions on a text literal, bind variable, or any column that holds
character data such as CHAR, NCHAR, CLOB, NCLOB, NVARCHAR2, and
VARCHAR2 (but not LONG).
And some more info to consider:
A string literal in a REGEXP function or condition conforms to the
rules of SQL text literals. By default, regular expressions must be
enclosed in single quotes. If your regular expression includes the
single quote character, then enter two single quotation marks to
represent one single quotation mark within the expression. This
technique ensures that the entire expression is interpreted by the SQL
function and improves the readability of your code. You can also use
the q-quote syntax to define your own character to terminate a text
literal. For example, you could delimit your regular expression with
the pound sign (#) and then use a single quote within the expression.
Note: If your expression comes from a column or a bind variable, then
the same rules for quoting do not apply.
Note there is no column type named RegEx, you would need to save the string as is, in a textual column.
Also you can use RegEx in constraint checking and when you project columns.
SQL Server (and probably some other SQL databases) supports this out of the box, though as has been noted before, this can only be executed by the database as a table scan -- something to keep in mind if you have large numbers of regexes. You just reverse the usual order of the LIKE operator:
create table demo.query
(
id int identity not null,
regex nvarchar(max),
primary key(id)
);
insert into demo.query (regex) values ('aa%');
select * from demo.query where 'aaaa' like regex;
Looks a little funny, but it's perfectly valid.
Adding to Ely's answer, thought of letting you all know that MySQL also supports this.
In http://sqlfiddle.com/, I tested with MySQL 5.6
Build schema:
CREATE TABLE rule (name VARCHAR(20), tot INT, exp VARCHAR(50));
INSERT INTO rule VALUES ('Tim', 3, 't+');
INSERT INTO rule VALUES ('Rob', 4, 'a\d+');
INSERT INTO rule VALUES ('Fil', 1, 'tt');
INSERT INTO rule VALUES ('Jack', 1, '^tt$');
INSERT INTO rule VALUES ('Marc', 1, 'bb');
COMMIT;
Test:
select * from rule where 'ttt' RLIKE exp ;
Expected: rows for Tim, and Fil

Regex to replace parameter names by values

I have a string that has a form:
UPDATE "TABLE"."ITEMS" SET ITM_DESCR=:sqldevvalue WHERE ROWID = :sqldevgridrowid AND ORA_ROWSCN = :sqldevgridrowscn
and its binding values as:
#1(11):Test Record #2(18):AAAG9IAAFAAAC0eAAB #3(7):7746161
How can I construct a regular expression to replace the parameter names (starting with :) with their corresponding values and create a combined string that has the form:
UPDATE "TABLE"."ITEMS" SET ITM_DESCR=Test Record WHERE ROWID = AAAG9IAAFAAAC0eAAB AND ORA_ROWSCN = 7746161
Here's a very simple, naive regex:
:(\w+)
Replace the match with the value, $1 contains the parameter name.
Here's a less naive attempt:
'(?:''|[^'])*'|:(\w+)
If $1 is set, replace the match with the value ($1 contains the paramter name), else do not replace. This version will let you handle situations like WHERE column = 'some text :not_a_param more text'
And... the not naive approach is to use prepared statements and SQL parameters with whatever SQL client you're using. This is the best option as it negates any risk of SQL injections if you do something wrong, and lets the DBMS cache the execution plan for your request.

How do you use RegEx to return a parsed value?

I have a data column that has a heading value with multiple levels, where I only want the first three levels, but I cannot figure out how to get the parsed value?
I was reading this and it shows how to use create a function to return a boolean for the condition, but how would I create a function that would return a parsed value?
This is the Regular Expression that I think I need.
^(\d.\d.\d)
I'm looking for something that would change 1.2.3.4.5. to 1.2.3 and similar for any other header I have that has more than three levels.
Ideally, I'd like to be able to put it into my Query Design as a Field Expression, but I'm not sure how I would do that.
I assumed your input values could have more than one digit between the dots. In other words, I think you want this ...
? RegExpGetMatch("1.2.3.4.5.", "^(\d+\.\d+\.\d+).*", 1)
1.2.3
? RegExpGetMatch("1.27.3.4.5.", "^(\d+\.\d+\.\d+).*", 1)
1.27.3
If that is the correct behavior, here is the function I used.
Public Function RegExpGetMatch(ByVal pSource As String, _
ByVal pPattern As String, _
ByVal pGroup As Long) As String
'requires reference to Microsoft VBScript Regular Expressions
'Dim re As RegExp
'Set re = New RegExp
'late binding; no reference needed
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
re.Global = True
re.Pattern = pPattern
RegExpGetMatch = re.Replace(pSource, "$" & pGroup)
Set re = Nothing
End Function
See also this answer by KazJaw. His answer taught me how to select the match group with RegExp.Replace.
In a query run within an Access session, you could use the function like this:
SELECT
RegExpGetMatch([Data Column], "^(\d+\.\d+\.\d+).*", 1) AS parsed_value
FROM YourTable;
Note however a custom VBA function is not usable for queries run from outside an Access session.
Try changing your RegEx to ^(\d\.\d\.\d). You need to escape the . since it has a special meaning in RegExp.