Neo4j-Multiple match statement in cypher query with if else conditon - java

I have to search certain nodes like eq.page whether or not they have relation or not with some other node..like tags.
If they are connected to tag nodes then search for the search string in page name and the tag names
Else search for the search string in page name only
MATCH ...//nodes of certain type
WHERE
if r is null'
...//Match query without relation for searching
else
...//Match query without relation for searching
Return ...
MATCH (n:page)<-[r:pagetag]-(tag)
if r is null
then n.title CONTAINS 'java'or tag.name IN ["java"]
return distinct n.name
else n.title CONTAINS 'java'return distinct n.name
END
This query is giving error. May be syntax problem. But I want to search for like this only for the pages.

Finally acheieved what I wanted. Thanks all. OPTIONAL Match worked great for me.
MATCH (s:page)
WITH s
OPTIONAL MATCH (s)<-[r:pagetag]-(tag)
WITH s,r,tag
Where s.pagename contains 'juniors'or tag.name contains 'math'
return distinct s.pagename

Isn't that just basic conditionals?
MATCH (n:page)<-[r:pagetag]-(tag)
WITH n,r,tag
WHERE r IS NULL AND (n.title CONTAINS 'java' or tag.name IN ["java"])
OR NOT r is NULL AND (n.title CONTAINS 'java')
return distinct n.name

I don't think you can use if else in Neo4j you have to use case, or foreach to simulate if .

Related

neo4j escaping for regular expressions

I receive a user input keyword and want to use it to search my database. I built a query that looks something like this:
db.execute("MATCH (n:User) WHERE n.firstname CONTAINS {keyword} OR n.lastname CONTAINS {keyword} RETURN n.username", params);
But this isn't case sensitive, so I thought of manually building the expression and using regular expressions, sort of as follows:
db.execute("MATCH (n:User) WHERE n.firstname =~ '(?i).*" + keyword + ".*' OR n.lastname =~ '(?i).*" + keyword + ".*' RETURN n.username");
I'm looking either for a function for escaping the regex or a better solution for making the query case-insensitive. Any ideas?
I would suggest storing the properties as all lowercase (or uppercase) and then using the Cypher lower() function to convert user input to lowercase for comparison.
Add lowercase name properties
MATCH (n:User)
SET n.lowerFirstName = lower(n.firstname),
n.lowerLastName = lower(n.lastname)
Find lower case matches based on user input
db.execute("MATCH (n:User) WHERE n.lowerFirstName CONTAINS lower({keyword}) OR n.lowerLastName CONTAINS lower({keyword}) RETURN n.username", params);

Java Neo4j Cypher Or Match

I have a graph were user can have a post and also can have a friend that have a post , the friend can be followed or not .
how can i query all the posts by the user and the friends that he is following ?
I tried this :
" MATCH (u1:User)-[:POSTED]->(p1:Post)"
+ " WHERE u1.username =~ '"+user+"'"
+ " OPTIONAL MATCH (u3:User)-[:FOLLOWING]->(u2:User)-[:POSTED]->(p2:Post),"
+ " (u3:User)-[:FRIEND_OF]->(u2:User)"
+ " WHERE u3.username =~ '"+user+"' return u1.username, u1.name,"
+ "p1 ,u2.username, u2.name , p2";
but this query returns duplicates, lets say we have our user and a friend .
the frien have one post and the user have two , the query returns the friend post twice its like for every MATCH the query returns also the result of OPTIONAL MATCH .
to further exaplain:
(u:User)-[:POSTED]->(p:Post)
(u:User)-[:FRIEND_OF]->(u2:User)
(u:User)-[:FOLLOWING]->(u2:User)-[:POSTED]->(p2:Post)
these are the relationships that exist what i want is all Posts (:Post) that meet those relationships without duplicates and preferably with single query .
First of all, your query is much more complex than it needs to be. This simpler query should be equivalent. I assume that {user} is supplied as a parameter.
MATCH (u1:User {username: {user}})-[:POSTED]->(p1:Post)
OPTIONAL MATCH
(u1)-[:FOLLOWING]->(u2:User)-[:POSTED]->(p2:Post),
(u1)-[:FRIEND_OF]->(u2)
RETURN u1.username, u1.name, p1, u2.username, u2.name, p2;
The reason you get multiple rows with the same p2 values is because your RETURN clause is returning values related to u1 and u2 together. If there are N u1/p1 results and M u2/p2 results, then you'd get N*M result rows.
To get a result with N rows (with one row per u1/p2 result), you can use something like this query:
MATCH (u1:User {username: {user}})-[:POSTED]->(p1:Post)
OPTIONAL MATCH
(u1)-[:FOLLOWING]->(u2:User)-[:POSTED]->(p2:Post),
(u1)-[:FRIEND_OF]->(u2)
RETURN
u1.username, u1.name, p1,
COLLECT({username: u2.username, name: u2.name, p2: p2}) AS friends;
Each result row will have a friends collection with the data for each relevant friend.

JAVA: NamedQuery String problem

Hello guys I am having some problems with exact matches while doing a NamedQuery.
I am currently using something like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from Entry e where e.name =:"+ Entry.NAME )
...
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName());
It works for most cases, however I noticed that in case the user pass the file name with an space at the end, the namedQuery ignores that character. For example:
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName()+ " ");
Will return the same result as the query before. Bypassing my 'valid entry' validation. In other words I'd like the query to return no entry at all and treat the error later on.
One workaround I could think of, is to put single quotes surrounding my parameter in the namedQuery, like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from entry e where e.name =':"+ Entry.NAME "'")
However it will trash my code in case the String contains single quotes in it...
Any ideas guys?
I guess this happens because your database field is declared as CHAR(...), and therefore stored values are padded with whitespaces which are not taken into account by = operation.
So, you may either declare your database field as VARCHAR(...) or use a built-in trim function:
query = "select e from Entry e where trim(trailing from e.name) =:"+ Entry.NAME
I did some research in JPA and found out that it does some automatic trimming for CHARs, I am not sure if this behaves the same with Strings, but since it is happening to me... I believe so. The only way to bypass it is by setting some attribute within the session DatabaseLogin object (see http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/sessions/DatabaseLogin.html#setShouldTrimStrings) .
Well I didn't want to be messing up with the session properties so I decided to make some sort of check and throwing the same exception as the NoResultException catch does in my code.
I basically took the result from the database and compared the field with the String I used:
query.setParameter(Entry.NAME, myEntry.getName());
...
if(!StringUtils.equals(result.getName(), myEntry.getName()){
do a cool throw just like NoResultException Catch
}
I also had to include the Trim function axtavt! This is just to make sure that if the database has a column with trailing spaces and it matches the parameter given by the user, it will be included as a valid answer. For example:
Database entry: Name = "Flavio " - Trimmed with Function = "Flavio".
Parameter passed: Name = "Flavio " - Trimmed by JPA automatic function = "Flavio".
If it isnt trimmed at all it will just Compare "Flavio " with "Flavio", returning NoResult when it was supposed to return that Entry.
Nasty workaround, but as long as there is no other way to stop the auto-trimming we will have to just make use of this sort of things.
Thanks for all the other answers!!

setFilter() with a string wildcard?

I see an example of doing a partial string search on the GAE google group (this thread):
String term1 = "cow";
String term2 = "horse";
Query q;
q.setFilter("name.matches('" + term1 + "%')");
so this works like:
"Find all objects of the class where property 'name' starts with term1"
so that would match stuff like:
cowfoo
cowgrok
cowetc
right? I could then replace term1 with term2, and find all instances that begin with 'horse'. Is there a doc that explains this anymore? I just want to check this is how it really works before I make a decision on how to store some strings for my data model,
Thanks
I can't find the docs which present the prefix matching syntax you presented, but your logic is sound. And it looks like the syntax is supported based on the google group message you cited.
For the Python runtime, I would perform a prefix match by using an inequality filter. You can also do this on the Java runtime like this (and this is probably how the % syntax is implemented):
// prefix is some string object
q.setFilter("my_string_field >= :1 && my_string_field < :2");
q.execute(prefix, (prefix + "\ufffd"));

REGEXP in MySQL Return unwanted value

I have problem using REGEX in Mysql
I have oid value in database like this
id -> value
1.3.6.1.4.1 -> Value a
1.3.6.1.4.1.2499.1.1.2.1.1.1.1.1 -> Value b
1.3.6.1.4.1.2499 -> Value c
And my objecttives are
1. To get single oid & value with the specific oid that i put into sql statement
2. If no specific value then it should reverse the oid number by number until it found the newrest value
For example
If i use
[select id from tablename where '1.3.6.1.4.1.2499.1.1.2.1.1.1.1.1' REGEXP oid]
it should return only 1.3.6.1.4.1.2499.1.1.2.1.1.1.1.1 but the above sql will return all result
If i use
[select id from tablename where '1.3.6.1.4.1.24999999.5' REGEXP oid]
it should return 1.3.6.1.4.1 only but it return 1.3.6.1.4.1 and 1.3.6.1.4.1.2499
If i use
select id from tablename where '1.3.6.1.4.1.2499.1.1.2.1.1.1.1.100' REGEXP oid
it should return 1.3.6.1.4.1.2499 only but it return all ids
I am not really familiar with this REGEXP. Can anyone help me to solve this problem.
Thank you
With MySQL, you should use field REGEXP value, like this:
select id from tablename where oid REGEXP '1.3.6.1.4.1.2499.1.1.2.1.1.1.1.1'
. must be escaped with \
And to match an entire row, use ^ and $:
select id from tablename where oid REGEXP '^1\.3\.6\.1\.4\.1\.2499\.1\.1\.2\.1\.1\.1\.1\.1$'
I don't understand why do you use REGEXP when you can select by LIKE, because you don't search by a regular expression.
I don't think regex is the right tool for this job.
Instead, I'd loop over the input string, treating it as a period-delimited list.
Match the list against oid. If zero matches, remove the last list element. Repeat.

Categories

Resources