How to make MATCH result mandatory with Cypher? - neo4j

I have a cypher looking like this:
CREATE
(a:LabelA {
uid: "01"
})
WITH * MATCH
(b:LabelB {uid: "02"})
MERGE (a)-[:RELATION]->(b)
If I do not have any node with uid "02" I would like to get an error. This cypher passes, but the relation (a)-[:RELATION]-(b) is not created (since the node 'b' does not exist).
How can I solve this?

Ter is no way to get error with your scenario if you are directly executing this query on neo4j. In case you are executing this query through some application via an API, then probebly you can write functionality to throw exception.

It is not an error for a MATCH pattern to not match anything.
If your code needs an error for some reason, then it should just generate an error when the query response indicates that there is no node with a uid value of "02".
For example, suppose you added an appropriate RETURN statement to your query:
MERGE (a:LabelA {uid: "01"})
WITH *
MATCH (b:LabelB {uid: "02"})
MERGE (a)-[:RELATION]->(b)
RETURN b;
Then, your code can check if any data rows are returned. If no rows are returned, then there is no node with the uid value "02".

Related

Removing a node from the Cypher query result in Neo4j

I have the following cypher code:
MATCH (n)
WHERE toLower(n.name) STARTS WITH toLower('ja')
RETURN n
This case-insensitive query returns all the nodes which their names start with the substring "ja". For example if I execute this in my db it will return ["Javier", "Jacinto", "Jasper", "Jacob"]
I need this script to also remove the unwanted nodes on this list, for example let's say that an array containing ["Jasper, Javier"] is sent to the data access layer indicating that those two nodes shouldn't be returned, leaving the final query result as follows: ["Jacinto", "Jacob"]
How can I perform this?
If you know before making the query which items should be excluded you can say:
MATCH (n)
WHERE toLower(n.name) STARTS WITH toLower('ja')
AND NOT (toLower(n.name) IN ['jasper', 'javier'])
RETURN n

Neo4j indices slow when querying across 2 labels

I've got a graph where each node has label either A or B, and an index on the id property for each label:
CREATE INDEX ON :A(id);
CREATE INDEX ON :B(id);
In this graph, I want to find the node(s) with id "42", but I don't know a-priori the label. To do this I am executing the following query:
MATCH (n {id:"42"}) WHERE (n:A OR n:B) RETURN n;
But this query takes 6 seconds to complete. However, doing either of:
MATCH (n:A {id:"42"}) RETURN n;
MATCH (n:B {id:"42"}) RETURN n;
Takes only ~10ms.
Am I not formulating my query correctly? What is the right way to formulate it so that it takes advantage of the installed indices?
Here is one way to use both indices. result will be a collection of matching nodes.
OPTIONAL MATCH (a:B {id:"42"})
OPTIONAL MATCH (b:A {id:"42"})
RETURN
(CASE WHEN a IS NULL THEN [] ELSE [a] END) +
(CASE WHEN b IS NULL THEN [] ELSE [b] END)
AS result;
You should use PROFILE to verify that the execution plan for your neo4j environment uses the NodeIndexSeek operation for both OPTIONAL MATCH clauses. If not, you can use the USING INDEX clause to give a hint to Cypher.
You should use UNION to make sure that both indexes are used. In your question you almost had the answer.
MATCH (n:A {id:"42"}) RETURN n
UNION
MATCH (n:B {id:"42"}) RETURN n
;
This will work. To check your query use profile or explain before your query statement to check if the indexes are used .
Indexes are formed and and used via a node label and property, and to use them you need to form your query the same way. That means queries w/out a label will scan all nodes with the results you got.

How to delete and merge outgoing relationships on the same query

I am using cypher. I am trying to delete all out going relationships before creating new ones on the same query.
i have weird situation if the relations/nodes already existed it's working as expected. if They never been created before I get:
(no changes, no rows)
This is my query:
match (user{userId:'a'})-[r:nearby_wifi]->() delete r
MERGE (p1:BT{userId:'a'}) WITH p1, [{bssid:"0a:18:d6:c1:3d:fd",level:"-51",timestamp:"1973-08-27 02:26:35.423",venueName:""},{bssid:"04:18:d6:c2:3e:2a",level:"-55",timestamp:"1973-08-27 02:26:35.425",venueName:""},{bssid:"0e:18:d6:c1:3d:fd",level:"-53",timestamp:"1973-08-25 11:06:07.392",venueName:""}] AS wifis
UNWIND wifis AS wifi
MERGE (p2:WIFI{bssid: wifi.bssid})
MERGE (p1)-[r1:nearby_wifi]->(p2)
SET r1.dist=wifi.dist
SET p1.lastTimeActive=1460378030215
SET p2.level=wifi.level
SET p2.timestamp=wifi.timestamp
SET p2.venueName=wifi.venueName
Any idea why when combining delete and the merge executions I got no changes(when graph empty)?
Thanks.
Replace first match with optional match
For example if you have no client nodes in your database, but have some person nodes query
Match (p:Client) with p Match (r:Person) return *
will get nothing, but query
Optional Match (p:Client) with p Match (r:Person) return *
will give you Persons. I think neo4j optimizer stops executing query after it gets no results and with optional match it gets null, and continues executing.

Multiple match with where clause in Neo4j Cypher gives error "Cannot match on a pattern containing only already bound identifiers"

We are using neo4j-community-2.1.2. Right now we have only 3 nodes Of Job label in the database And we do Schema indexing on all fields that are used in this query . Total DB hits approx 40
Query is ->
PROFILE match (job1:Job) where (job1.jobType="Adhoc" or job1.jobType="Virtual") AND (job1.mode="Free" or job1.mode="Paid") with collect(job1) as jobs1
match (job2:Job)-[REQUIRED_SKILL]-(skill:Skill) where skill.name="Neo4j" and (job2 in jobs1) with collect(job2) as jobs2
match (job3:Job)-[REQUIRED_SKILL]-(skill:Skill) where skill.name="Java" and (job3 IN jobs2) with collect(job3) as jobs3 return jobs3
So we try to do something like that
match (job1:Job) where (job1.jobType="Adhoc" or job1.jobType="Virtual")
match (job1) where (job1.mode="Free" or job1.mode="Paid") with collect(job1) as jobs1 return jobs1
Because result of first match goes to next match . So that in next filter there is only need to filter less number of nodes But we get this exception
Cannot match on a pattern containing only already bound identifiers (line 2, column 1)
"match (job1) where (job1.mode="Free" or job1.mode="Paid") with collect(job1) as jobs1 return jobs1"
Optimize this Query
You cannot match job1 twice, once it is matched you can use the same instance again (using WITH), or in this case, you can filter on both conditions using AND. Also your query would be simpler by replacing OR with IN inclusion test, like this:
match (job1:Job)
where job1.jobType in ["Adhoc", "Virtual"]
and job1.mode in ["Free", "Paid"]
return collect(job1) as jobs1

neo4j: how to query subgraph

I want to select a subgraph(S) from my neo4j database and use another query on S to find if two given nodes are connected. Is there a way to write a query in neo4j ? I'm using node.js and Cypher.
EDIT:
I'm doing something similar to this, for example:
Match (u:User)-[:adds]->(y:Paper)-[:consistsOf]->(e:L2)-[]->(m:L3)
where u.username = 'test'
MATCH p=(m:L3)-[r:gives*1..4]->(n:L3)
...
Thanks
In your example, you could use the WITH clause to connect the 2 MATCH statements, like this (cleaned up a little):
MATCH (u:User {username:'test'})-[:adds]->(y:Paper)-[:consistsOf]->(e:L2)-->(m:L3)
WITH m
MATCH p=(m)-[r:gives*1..4]->(n:L3)
...
The WITH clause is like RETURN, except that its purpose is to pass value(s) from one query to the next. In this case, only 'm' is being passed, and so the second MATCH will not be aware of 'u', 'y', or 'e'.

Resources