Handling special chars in a case insensitive search - neo4j

I am using:
c.customerName =~ '(?i).*$q.*'
in order to find insensitive case any kind of customername and this is working absolutely fine for all standard character. In German unfortunately there are special chars e.g. like Ä,Ö,Ü. In this cases the cypher statement is case sensitive, e.g. if we have two customer names like Ötest and ötest it will find only one of them depending if you type a lower or an upper Ö.
Anyone has a hint what I can do to expand the insensitive case search also on such special chars?
EDIT: The problem exists also when you have a name including e.g. a '&' - you'll find e.g. the company D&A Construction when you type 'D&' - the moment you add a thrid character 'D&A' the search fails and no result is shown. Any idea?

You need to add a 'u' in your regex to transform it in a case-insensitive unicode regex. Like this:
c.customerName =~ '(?ui).*$q.*'
Works here:
From this StackOverflow question.

Related

Neo4j - search like query with non english characters

Is there an option in neo4j to write a select query with where clause, that ignores non-latin characters ?
MATCH (places:Place)
WHERE (places.name =~ '.*(?ui)Fabergé.*')
RETURN places
I have place with Fabergé name in graph and i want to find it when user type Fabergé or Faberge without this special character.
I'm not aware of an easy way to do this directly with a regex match in Cypher.
One possible workaround is to store the string in question in a normalized form in a second property e.g. place.name_normalized and then compare it with the normalized search string. Of course normalization needs to be done on client side, see another SO question on how to achive this: Remove diacritical marks (ń ǹ ň ñ ṅ ņ ṇ ṋ ṉ ̈ ɲ ƞ ᶇ ɳ ȵ) from Unicode chars

Rails query by number of digits in field

I have a Rails app with a table: "clients". the clients table has a field: phone. phone data type is string. I'm using postgresql. I would like to write a query which selects all clients which have a phone value containing more than 10 digits. phone does not have a specific format:
+1 781-658-2687
+1 (207) 846-3332
2067891111
(345)222-777
123.234.3443
etc.
I've been trying variations of the following:
Client.where("LENGTH(REGEXP_REPLACE(phone,'[^\d]', '')) > 10")
Any help would be great.
You almost have it but you're missing the 'g' option to regexp_replace, from the fine manual:
The regexp_replace function provides substitution of new text for substrings that match POSIX regular expression patterns. [...] The flags parameter is an optional text string containing zero or more single-letter flags that change the function's behavior. Flag i specifies case-insensitive matching, while flag g specifies replacement of each matching substring rather than only the first one.
So regexp_replace(string, pattern, replacement) behaves like Ruby's String#sub whereas regexp_replace(string, pattern, replacement, 'g') behaves like Ruby's String#gsub.
You'll also need to get a \d through your double-quoted Ruby string all the way down to PostgreSQL so you'll need to say \\d in your Ruby. Things tend to get messy when everyone wants to use the same escape character.
This should do what you want:
Client.where("LENGTH(REGEXP_REPLACE(phone, '[^\\d]', '', 'g')) > 10")
# --------------------------------------------^^---------^^^
Try this:
phone_number.gsub(/[^\d]/, '').length

Case Insensitive Search with Neo4jClient

Just an quick and easy one, I need to be able to search our database minus the case sensitivity, I know how to do it, just not with the Neo4jClient. Here's the code:
client.Cypher
.Match("(person:Person)")
.Where((Person person) => person.Email == search)
where 'search' is a parameter of type string that is passed to the method. I have read that using =~ '(?i)text' works, but that doesn't allow me to pass in the parameter, and I have tried this:
client.Cypher
.Match("(person:Person)")
.Where((Person person) => person.Email =~ "(?i){terms}")
.WithParam("terms",search)
But it doesn't like this.
I would like to be able to search without case, and if possible at the same time, using LIKE (or ILIKE as it seems to be for pattern matching).
Thanks
EDIT & ANSWER
The final code ended up as this:
return client.Cypher
.Match("(person:Person)")
.Where("person.Email =~ {terms}")
.OrWhere("person.Name =~ {terms}")
.WithParam("terms", "(?ui).*" + search + ".*")
.Return<Person>("person").Results.ToList();
Which does exactly what I want it to.
Also took the advice of a lowercase field with the value in, we already have one in the account so that logon names are not case sensitive, I am going to do this on the email and name fields, seems better than using toLower() (either in Cypher or in C#)
So thank to #Stefan Armbruster for his help.
You cannot have partial parameters. Instead add (?i) to the parameter value:
query: person.Email =~ term
parameter: term = "(?i)<myvalue"
Note 1: You need to use (?ui) for gracefully dealing with non-ascii case sensitivity (e.g. German umlauts).
Note 2: the =~ operator is not backed by an index, so the query above will touch every Person node and apply the regex to the property value. In Neo4j 2.3 there will be a index backed LIKE which supports string prefix matches.
If you want to use index based case insensitive search, the recommended approach is to store the property value converted to lower case (Cypher has a toLower function) and then do a exact match on the lower cased search value.

Heroku/postgresql search

I have a database with names of cities that uses all different kinds of characters, from åäö to vietnamese signs. The place names are all in a capitalized format e.g. "New York" and "Aix En Provence".
My problem now is to try to search for these city names in Heroku which uses postgresql.
p = Place.where("upper(name) LIKE '%" + place_name_searched.to_s.upcase.tr('åäöüñï','ÅÄÖÜÑÏ') + "%'").first
This is the best I have come up with but it is only but a fix for åäö etc and doesn't catch all the 100+ different characters there is out there, e.g. "é". The solution is not to fill out that string any further.
A general problem is that upper(name) seems to translate everything fine but upcase can only handle english letters. So the correspoding search will be .where("TÄBY like 'TäBY') if place_name_searched = 'täby'.
So, how can I match postgresql entries such as "Täby" and "Jidd Ḩafş" to corresponding strings in downcase, entered by the user ("täby", "jidd hafs")?
It all works fine in my Mysql-version of the application but once I upload to Heroku it all fails.
Postgres has an extension called "ILIKE" for case insensitive pattern matching.
p = Place.where("upper(name) ILIKE '%" + place_name_searched.to_s.upcase.tr('åäöüñï','ÅÄÖÜÑÏ') + "%'").first
But please note this only works with Postgres, so you need to check which environment you are running on to decide if you would use this one instead of the regular one.

Case insensitive searching for words in mongoid

Is there a way to set an attribute in mongoid for case insensitive searches?
Lets say that somebody has a username: IAmGreat and I want to find the users data using their unique username without butchering it and changing it to iamgreat.
Thanks
Actually you can search case insensitive. But you have to search with an regex!
Here is an example how I'm using it at http://zeit.io
User.where(email: /\A#{Regexp.escape(email)}\z/i).first
With the / you are starting and ending the regex. The i after the regex means case insensitive. \A Means the string has to start with the search string and \z means the string has to end with the search string. This is important if you are looking for an exact match.
You can even try something like:
User.where(username: /#{username}/i).first
if you are using rails or mongoid you can try the ff:
#user = User.where({:username => /.*#{name}.*/i })
Why not just down a User.login.downcase (or whatever your model/attribute combination is) when making the comparison? This will leave the capitalization in the DB as-is, but downcase the field just for comparison.
If your application doesn't need to store user-input as case-sensitive, just convert the input to uppercase or lowercase on the way in. Example,
username = params[:username].to_s.downcase
Otherwise, if performance is an issue for you (case-insensitive regex cannot take advantage for indexes) the right way to go about it is to store a backup field for username
field :username_downcase
And then do the query:
User.where(username_downcase: params[:username].to_s.downcase)

Resources