How do I write this Neo4j Query? - neo4j

There are three node types: A, B and C.
I need all the A's and B's and only the C's that participate in exactly one relationship.
match (n)
where n:A or n:B or (n:C)-[]-()
with count(n) as countOfRels
where countOfRels > 0
return n
Not close, I know. I'm not sure where to go from here.

It's a bit strange that A, B and C do not seem to be related ... but here's how you could solve your question for C :
MATCH (n:C)
WHERE size((n)-[]-()) = 1
RETURN n
UNION
MATCH (n:A)
RETURN n
UNION
MATCH (n:B)
RETURN n;
Hope this helps.
Regards,
Tom

you can use this
match(n)
where n:A OR n:B OR (n:C)-[r]-()
with count(r) as countOfRels
where countOfRels > 0
return n
Hope this helps.

You can do MATCH (a)--() WHERE NOT ()--(a)--() to match "nodes with only one relation". After that, You can use UNION or COLLECT()+UNWIND to combine the separate queries into one row result set.
// using Union
MATCH (n:C)--()
WHERE NOT ()--(n)--()
RETURN n
UNION
MATCH (n:A)
RETURN n
UNION
MATCH (n:B)
RETURN n;
// Using collect
OPTIONAL MATCH (a:A)
OPTIONAL MATCH (b:B)
OPTIONAL MATCH (c:C)--() WHERE NOT ()--(c)--()
WITH COLLECT(a)+COLLECT(b)+COLLECT(c) as nodez
UNWIND nodez as n
RETURN DISTINCT n

Related

Neo4j Cypher: Find isolated node

I want to find nodes that do not connect with other nodes. (node A and node B in the picture below)
What I have tried is
MATCH (n:node) WHERE not ((n)<-[:connect]->(:node)) RETURN n
which seems to return only B.
How can I retrieve both A and B?
Thank you in advance!
[UPDATED]
This will work if you only care about connect relationships:
MATCH (n:node)
WHERE SIZE([(n)-[:connect]-(m:node) WHERE n <> m|1]) = 0
RETURN n
But if you want to pay attention to all relationship types, then use this:
MATCH (n:node)
WHERE SIZE([(n)--(m:node) WHERE n <> m|1]) = 0
RETURN n

Query to write hops and return all the properties from the middle nodes or a better way to do it and skip hops?

Node A is connected to Node E through different nodes B (B can be repeating), C and D etc as given below.
(A)--(C)--(D)--(E)
(A)--(B)--(C)--(D)--(E)
(A)--(B)--(B)--(C)--(D)--(E)
(A)--(B)--(B)--(B)--(C)--(D)--(E)
There could be up to 7 B nodes between A and C or no B node at all (like the first case above).
Question: How to get all the E1, E2, E3, E4 connected to A1 with a single query and return properties from all A, B, C, D and E nodes? I could not return the properties using the hops.
MATCH (A {Id:30})-[*1..6]-(E) RETURN DISTINCT A.Name, E.Name;
But we want to return B.Name (If there are multiple B nodes in the middle their names too), C.Name and D.Name too. Happy to skip hopping completely if required. Help please? Thanks in advance.
Try this
// in case there is always A,C and E, you can look for
// paths with length 3 to 6
MATCH path=(A)-[*3..6]-(E)
// return the name of each node in the same order
RETURN [n IN nodes(path) | n.name] AS nodeNames
Assuming A through E are node labels, this query should get all paths that match your pattern (with 0 to 7 B nodes between the A and C nodes), and return distinct lists of node Name values:
MATCH p=(:A)-[*..8]-(:C)--(:D)--(:E)
WHERE ALL(n IN NODES(p)[1..-3] WHERE 'B' IN LABELS(n))
RETURN DISTINCT [m IN NODES(p) | m.Name] AS names
In general, the query would be more efficient if you could also specify the relationship types and their directionality.

cypher multiple match is very slow

I want to match some node which don't satisfy the condition, but it's very slow. How to optimize it? There are about 70000 nodes in the database.
match (n:A)--(p:B)--(q:C)
with collect(n) as nc
match m where not m in nc
return count(m)
There is no need to first get all the nodes that match an initial pattern. It is enough to go through all the nodes and check them:
MATCH (m) WHERE NOT (m)--(:B)--(:C)
RETURN count(m)
Or if the condition on the label 'A' is important:
MATCH (m)
OPTIONAL MATCH p = (m)--(:B)--(:C)
WITH m WHERE (p IS NULL) OR (NOT p IS NULL AND NOT 'A' IN LABELS(m))
RETURN count(m)

Neo4j : how to match nodes that have a common value in a property array

I have nodes with an "id" property array:
node 1: {id:[1,2,3]}
node 2: {id:[3,4,5]}
node 4: {id:[6,7,8]}
I want a query to match the node pairs that have at least one common value in the ID property array; for example the query I'm looking for would return only node 1, node 2 (they have the value "3" in common).
I've tried this, but it didn't work for me:
MATCH (n), (m) where FILTER(x IN n.id WHERE x IN m.id) return n,m;
Thanks!
Actually, your original query should have returned some results.
Here is an improved version of that query:
MATCH (n), (m)
WHERE ID(n) < ID(m) AND ANY(x IN n.id WHERE x IN m.id)
RETURN n, m;
It avoids duplicate results by ordering the nodes by ID.
It use the ANY function, which exits as soon as a match is found.
See this console.
This is a bit convoluted, but it seems to work:
MATCH n, m
WHERE ID(n)< ID(m)
WITH n, n.id AS n_ids, m, m.id AS m_ids
UNWIND n_ids AS n_id
UNWIND m_ids AS m_id
WITH n, m, n_id, m_id
WHERE n_id = m_id
RETURN n, m
If that doesn't make sense to you, I'd suggest you try changing each WITH to a RETURN and removing everything afterwards to see the results at each step.
EDIT: You can also make this a bit shorter thusly:
MATCH n, m
WHERE ID(n)< ID(m)
WITH n, n.id AS n_ids, m, m.id AS m_ids
UNWIND n_ids AS n_id
WITH n, m, n_id, m_ids
WHERE n_id IN m_ids
RETURN n, m
(You might need a DISTINCT in there at the end for a larger dataset)

Using Union results to filter a match using With

I wish to use the results of a UNION (n) as a filter for a subsequent match.
MATCH (n:Thing)-<<Insert valid match filters here>>
RETURN n
UNION
MATCH (n:Thing)-<<Insert a different set of match filters here>>
RETURN n;
n feeds into:
MATCH (n)-[:RELTYPE1]->(a:Artifact);
RETURN a;
I would expect to use a WITH statement, but I've struggled to figure out how structure the statement.
MATCH (n:Thing)-<<Insert valid match filters here>>
RETURN n
UNION
MATCH (n:Thing)-<<Insert a different set of match filters here>>
WITH n
MATCH (n)-[:RELTYPE1]->(a:Artifact);
RETURN a;
This was my original attempt, but the WITH is interpreted as the start of subquery of the UNION's second match (which makes sense).
I can see a few inelegant ways to make this work, but what is the proper approach?
I have been looking at your union example and it makes sense to me but I cannot see how I could make it work. But I am certainly not the guy with all of the answers. Is there a reason you couldn't do something like this though...
MATCH (n:Thing)
WHERE n.name = 'A'
WITH collect(n) as n1
MATCH (n:Thing)
WHERE n.name = 'B'
WITH n1 + collect(n) AS both
UNWIND both AS n
MATCH (n)-[:RELTYPE1]->(a:Artifact);
RETURN a;

Resources