I am in need of get data of whether there is no relation exists between two labels and condition based data on one of labels. I found an answer following ::
MATCH (n:Label1)
WHERE NOT (n)-[:REL_1]-(:Label2)
OR (n)-[:REL_1]-(e:Label2 {id:1})
RETURN count(DISTINCT(n))
But What I need is like all of id>=5 data should come in result
If I perform a query like ::
MATCH (n:Label1)
WHERE NOT (n)-[:REL_1]-(:Label2)
OR (n)-[:REL_1]-(e:Label2)
WHERE e.id >= 5
RETURN count(DISTINCT(n))
It is producing error ::
Invalid input 'H': expected 'i/I' (line 1, column 94 (offset: 93))
[UPDATED]
A Cypher query cannot have 2 WHERE clauses in a row. In addition, you have not defined the e identifier.
This query should work (I assume you only want to count n if it does not have such a relationship OR if it has at least one in which e.id is at least 5):
MATCH (n:Label1)
OPTIONAL MATCH (n)-[:REL_1]-(e:Label2)
WITH n, e
WHERE e IS NULL OR e.id >= 5
RETURN count(DISTINCT n);
You can nest WHERE filters, you just have to give up syntactic sugar to do it.
MATCH (n:Label1)
WHERE ALL(p IN (n) - [:REL_1] - (:Label2) WHERE LAST(NODES(p))['id'] >= 5)
RETURN COUNT(n)
You reconstruct any match-filter construct you can dream of with the ANY, ALL, NONE toolset, which allow you to apply filters internally as well and nest the iterable component (between IN and `WHERE) to multiple depths.
Related
I have two types of relationship that can exist between two same nodes. I want to extract the nodes that only have type1 and not type2 relationship. My query is:
Match (n) where (n)-[:type1]-(m) and (not (n)-[:type2]-(m)) return n
This gives error:
PatternExpressions are not allowed to introduce new variables: 'm'. (line 1, column 32 (offset: 31))
"Match (n) where (n)-[:type1]-(m) and (not (n)-[:type2]-(m)) return n"
^
Neither Googling around nor the documentation Patterns - Neo4j Cypher Manual give me any useful help. Do you know why is this?
How about this.
match(n)-[:type1]-(m)
where not (n)-[:type2]-(m)
return n
Is it possible to get all relationships in a graph without the nodes?
I'm trying
MATCH [r:MEMBER]
RETURN r
But it gives me the error
Invalid input '[': expected whitespace, comment or a pattern (line 1, column 7 (offset: 6))
"MATCH [r:MEMBER] reTURN r"
^
You need to match a relationship pattern:
MATCH ()-[r:MEMBER]-()
RETURN r
Since Neo4j's relationships always have a direction, this is the fastest.
MATCH ()-[r:MEMBER]->()
RETURN r
Neo4j's browser will not display a graph, but just return the property maps of the relationships.
So as a complication to this question, I basically want to do
MATCH (n:TEST) OPTIONAL MATCH (n)-[r]->() RETURN DISTINCT n, r
And I want to return n and r as one column with no repeat values. However, running
MATCH (n:TEST) OPTIONAL MATCH (n)-[r]->() UNWIND n+r AS x RETURN DISTINCT x
gives a "Type mismatch: expected List but was Relationship (line 1, column 47)" error. And this query
MATCH (n:TEST) RETURN DISTINCT n UNION MATCH ()-[n]->() RETURN DISTINCT n
Puts nodes and relationships in the same column, but the context from the first match is lost in the second half.
So how can I return all matched nodes and relationships as one minimal list?
UPDATE:
This is the final modified version of the answer query I am using
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r {properties:properties(r), id:id(r), type:type(r), startNode:id(startNode(r)), endNode:id(endNode(r))})} as n
There are a couple ways to handle this, depending on if you want to hold these within lists, or within maps, or if you want a map projection of a node to include its relationships.
If you're using Neo4j 3.1 or newer, then map projection is probably the easiest approach. Using this, we can output the properties of a node and include its relationships as a collected property:
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r)} as n
Here's what you might do if you wanted each row to be its own pairing of a node and a single one of its relationships as a list:
...
RETURN [n, r] as pair
And as a map:
...
RETURN {node:n, rel:r} as pair
EDIT
As far as returning more data from each relationship, if you check the Code results tab, you'll see that the id, relationship type, and start and end node ids are included, and accessible from your back-end code.
However, if you want to explicitly return this data, then we just need to include it in the query, using another map projection for each relationship:
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r {.*, id:id(r), type:type(r), startNode:startNode(r), endNode:endNode(r)})} as n
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.
I want to return the count of the union statement, but I'm having a little trouble with my return statement.
Given a venn diagram, the union is the sum of the "areas" of the two circles minus the intersection between them. I'm trying to emulate this, but I ran into a little trouble because Booleans don't convert into ints.
I'm trying to return something like this:
COUNT(DISTINCT a.name) + COUNT(DISTINCT b.name) - (a.name == b.name)
You can do CASE WHEN a.name = b.name THEN 1 ELSE 0 END (and do sum on that, or something). However, you might have dups if you're doing distinct of the other two--maybe you need to adjust something in the rest of your query to avoid duplicates, if you can give us more detail.
If we assume your original query looked like the first UNION example in the neo4j 2.1.5 cheat sheet:
MATCH (a)-[:KNOWS]->(b)
RETURN b.name
UNION
MATCH (a)-[:LOVES]->(b)
RETURN b.name
Then you can get the count of the number of distinct names in the UNION this way:
OPTIONAL MATCH (a)-[:KNOWS]->(b)
WITH COLLECT(DISTINCT b.name) AS n1
OPTIONAL MATCH (c)-[:LOVES]->(d)
WITH COLLECT(DISTINCT d.name) AS n2, n1
RETURN LENGTH(filter(x IN n2 WHERE NOT (x IN n1))) + LENGTH(n1)
I don't see a way to use an actual UNION statement to calculate the answer.
This may be a bit more cypher than you planned to write but I was recently in a similar situation and I ended up putting the sets and intersection in collections and figuring out the resulting difference.
I am sure there is a better way but this is what i came up with. Essentially, I found set 1 and set 2 and put them each in a collection. Then I found the intersection by finding all of the things that were the same and put them in another collection called the intersection. then I just filtered down each of set1, and set2 against the intersection. In the end I am left with two sets that contain the nodes out of the intersection.
match (things_in_set_1)
where <things in set 1 criteria>
with collect(things_in_set_1.name) as set1
match (things_in_set_2)
where <things in set 2 criteria>
with collect(things_in_set_2.name) as set2, set1
optional match (things_in_set_1),(things_in_set_2)
where things_in_set_1.name = things_in_set_2.name
with collect(things_in_set_1.name) as intersection, set1, set2
with filter( id IN set1 WHERE not(id in(intersection)) ) as set_unique_nodes1, set2, intersection
with filter( id IN set2 WHERE not(id in(intersection)) ) as set_unique_nodes2, set_unique_nodes1
return length(set_unique_nodes2) + length(set_unique_nodes1)