neo4j: How do I query multiple properties for the same string? - neo4j

I'm very new to neo4j and code generally. I'm trying to query multiple properties of my nodes for the same string, but don't want to have to type out my string in several times for each search.
For instance, right now my code is:
START b=node(*)
WHERE (b.name =~ '(?i).*edward.*' OR b.alias =~ '(?i).*edward.*')
RETURN b
Which means that I have to type out 'edward' twice for each search. Is there a way to avoid this?

You need the ANY function:
MATCH (b)
WHERE ANY(k IN ['name', 'alias'] WHERE toString(b[k]) =~ '(?i).*edward.*')
RETURN b

Define you regex in a parameter and use it like this:
:param regex: '(?i).edward.'
START b=node(*)
WHERE (b.name =~ $regex OR b.alias =~ $regex)
RETURN b

Related

efficient querying of array property in neo4j

I've wanting to query for nodes that have a specific value in a string array property. For instance my nodes might have 2 properties, name (a string) and aliases (a string array). I have created an index on both properties using something like CREATE INDEX ON :F2(name).
I can query the name property using something cypher like this, and the result is immediate:
MATCH (p:F2) WHERE p.name = 'john' RETURN p;
I can query the aliases property using cypher like this, and I get the expected result but the response is very slow:
MATCH (p:F2) WHERE ANY(item IN p.aliases WHERE item = 'big john') RETURN p;
This looks like either the query is not optimal or the index is not being used.
Can someone suggest how to do this correctly. I'm pretty new to neo4j and cyper :-(
You could refactor your graph to make alias a node. So that any F2 node has zero or more aliases.
CREATE INDEX ON :Alias(name)
Then you could query it with something like this...
MATCH (p:F2)-[:HAS_ALIAS]->(:Alias {name: 'big john'})
RETURN p

Cypher query: CONCAT and TOKENIZE in the SET clause

I need to generate a cypher query where I should SET the value of one property based on the value of the other property as like this -
MATCH (n) SET n.XXX = n.YYY return n;
So XXX will be set to YYY. But YYY has values like this - "ABCD.net/ABC-MNO-XYZ-1234" and I should eliminate all the special characters (/,- etc) and then concat the splitted substrings. So the logical statement should be like -
MATCH (n) SET n.XXX = CONCAT(SPLIT(n.YYY, "/")) return n;
Neo4j doesn't have any CONCAT function. So how is it possible to accomplish this stuff in a cypher query?
Any help will be highly appreciated.
Thanks
You could do this:
MATCH (n:SomeNode) set n.uuid = reduce(s="",x in split(n.uuid,'/')| s+x)
and run this query for every special character.
If there are a lot of special characters, write this query:
UNWIND ['/','#'] as delim match (n:SomeNode) set n.uuid = reduce(s="",x in split(n.uuid,delim)| s+x)
Replace '/','#' with a list of your special characters.
Your use case really looks like you want removal of characters in the string, and neo4j does offer a replace() function that you can leverage for this.
But in the event that you do want a join(), the APOC Procedures library has this among the text functions it offers.

Replace regular expressions in cypher

I can search for regular expressions in cypher
MATCH (n:model) WHERE n.name =~ '.*&.*;.*' RETURN n.name
but can I also replace them? I would like to write something like
MATCH (n:model) RETURN replace(n.name, ~'&.*;', '_');
There is a replace function in cypher, but it does not replace regexps, just simple strings.
Maybe a feature request for replaceRegex could be done?
An workaround would be to do this programatically, after you return the names (if you use call cypher queries from another application).

Neo4j rename property using regex of current property value

From my research (lots of Googling), I can not see that this is possible, but it is still worth asking I think. I have a large collection of nodes like:
(org:Organization {name: "Organization 1234"})
where 1234 can be any non-negative integer.
In order to update the DB to work with a new API, I am wanting to rename each of these in the collection so that the result would look something like:
(org:Organization {name: "Org_1234"})
So, I need to mashup Org_ with the [0-9]+ regex match on the current property.
Truly, I am at a loss on where to even start. All I see in the documentation is that regex can be used as a predicate in the WHERE clause (WHERE n.property =~ {regex}). Is there a way using just Cypher as I am not using a Java library?
Assuming there is always a single space between "Organization" and the integer, you can brute force this pretty easily with just string functions.
CREATE (:Organization {name:'Organization 1234'}),
(:Organization {name:'Organization 5678'})
MATCH (o:Organization)
WITH o, SPLIT(o.name, " ")[1] AS id
SET o.name = "Org_" + id
RETURN o.name
Which returns
o.name
Org_1234
Org_5678

Running a case-insensitive cypher query

Is it possible to run a case-insensitive cypher query on neo4j?
Try that: http://console.neo4j.org/
When I type into this:
start n=node(*)
match n-[]->m
where (m.name="Neo")
return m
it returns one row. But when I type into this:
start n=node(*)
match n-[]->m
where (m.name="neo")
return m
it does not return anything; because the name is saved as "Neo". Is there a simple way to run case-insensitive queries?
Yes, by using case insensitive regular expressions:
WHERE m.name =~ '(?i)neo'
https://neo4j.com/docs/cypher-manual/current/clauses/where/#case-insensitive-regular-expressions
Another way would be:
WHERE LOWER(m.Name) = LOWER("Neo")
And if you are using the Neo4j Client (.NET):
Client.Cypher.Match("(m:Entity)")
.Where("LOWER(m.Name) = LOWER({name})")
.WithParam("name", inputName)
.Return(m => m.As<Entity>())
.Results
.FirstOrDefault();
If anybody is looking on how to do this with a parameter, I managed to do it like this.
query = "{}{}{}".format('Match (n) WHERE n.pageName =~ "'"(?i)", name, '" RETURN n')
and "name" is the variable or your parameter
You can pass a parameter to the case insensitive regular expression like:
WHERE m.name =~'(?i)({param})

Resources