cypher query without any return rows after modifying it using pattern comprehension - neo4j

This cypher query on the neo4j movie dataset will return 822 rows
MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
WHERE m.year = 2000
AND a.born IS NOT NULL
RETURN DISTINCT a.name AS Actor, a.born AS Born
order by a.born
I modify the query using pattern comprehension below and it returns 15443 rows, but all of them are empty arrays.
MATCH (a:Actor)
with a, [ (a where a.born is not null)-[:ACTED_IN]->(m:Movie where m.year = 2000) | a.name ] as Actors
return Actors
My intent is to return a list of actors just like the first query. What went wrong in the second query?

[UPDATED]
This will give you the distinct actors:
WITH [(a:Actor WHERE a.born IS NOT NULL)-[:ACTED_IN]->(m:Movie WHERE m.year = 2000)|a.name] AS actorList
UNWIND actorList AS actor
RETURN DISTINCT actor

Related

Neo4j count the number of related nodes

I'm starting studying the Neo4j and the Cypher Queries, and I need some help to understand and get some results.
I have this MATCH query:
MATCH (p:EntidadePessoa {id: 168750})-[rd:SE_RELACIONA]->(d:Documento)<--(p2)
where p2:EntidadePessoa or p2:EntidadeOrganizacao
return p,d,p2
That results this:
Commencing with EntidadePessoa id:168750, I want the count of EntidadeDocumento directcly linked to EntidadePessoa id:168750, is this case 2, and the count of each Entidade* that is linked to EntidadeDocumento, in this case 4 for each EntidadeDocumento.
I tried some queries, but none give me the results I wanted, the count number is never the numbers I wanted.
Could you help with that?
A query to get the count of d nodes connected to p (id: 168750).
MATCH (p:EntidadePessoa {id: 168750})-[rd:SE_RELACIONA]->(d:Documento)
RETURN p.id as `nodeId`, count(d) as `connectedCount`
output:
nodeId connectedCount
168750 2
A query with a subquery to look at just d:Documento, incoming links from p2, omitting (p:EntidadePessoa {id: 168750}) and counting p2s for each d node:
CALL
{MATCH (p)-[rd:SE_RELACIONA]->(d:Documento)
WHERE p.id=168750
RETURN d,p.id as `topid`}
MATCH (p2)-->(d)
WHERE (p2:EntidadePessoa or p2:EntidadeOrganizacao) AND p2.id<>topid
//p2.id<>topid ensures p is not included in count(p2)
RETURN d.id as `nodeId`, count(p2) as `connectedCount`
output:
nodeId connectedCount
164532 4
164552 4
Combine both these results with a UNION:
MATCH (p:EntidadePessoa {id: 168750})-[rd:SE_RELACIONA]->(d:Documento)
RETURN p.id as `nodeId`, count(d) as `connectedCount`UNION
CALL
{MATCH (p)-[rd:SE_RELACIONA]->(d:Documento)
WHERE p.id=168750
RETURN d,p.id as `topid`}
MATCH (p2)-->(d)
WHERE (p2:EntidadePessoa or p2:EntidadeOrganizacao) AND p2.id<>topid
//p2.id<>topid ensures p is not included in count(p2)
RETURN d.id as `nodeId`, count(p2) as `connectedCount`
output:
nodeId connectedCount
168750 2
164552 4
164552 4
This will give you the result. This is similar to count and group_by in sql.
MATCH (p:EntidadePessoa {id: 168750})-[rd:SE_RELACIONA]->(d:Documento)<--(p2)
where p2:EntidadePessoa or p2:EntidadeOrganizacao
With p, count(distinct d) as cnt_d, count(p2) as cnt_p2
return p, cnt_d, cnt_p2

Neo4j Cypher- With clause query

I'm doing some codes on the Neo4j's movies dataset the question was
Retrieve the actors who have acted in exactly five movies, returning the name of the actor, and the list of movies for that actor.
I wrote this following query and im not getting the result and it shows "no changes no result"
MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
WITH a,m, count(m) AS numMovies
WHERE numMovies = 5
RETURN a.name,collect(m.title) AS movies
where as when I wrote this query for the same satement this time I just write the "collect(m.title) AS movies " in the WITH clause and I got the desired result.
MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
WITH a, count(m) AS numMovies, collect(m.title) AS movies
WHERE numMovies = 5
RETURN a.name, movies
My doubt is that why result varies when I wrote the "collect(m.title) AS movies" in the RETURN clause.
Your first query has m, count(m), which will result in a count of 1 for each Movie node m.
You can check this by returning from the query in the second line:
MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
RETURN a, m, count(m) AS numMovies
The solution is to remove the separate m variable from the WITH clause as shown in your second query.

NEO4J: get movies where some actors of a given did not act

Using the movie graph, I have the following question: movies where Keanu Reeves AND Robin Williams did not act?
To solve this I have these two queries:
MATCH (m:Movie)<-[:ACTED_IN]-(p:Person)
WITH m, collect(p) as actors
WHERE NONE (actor in actors WHERE actor.name IN ['Keanu Reeves', 'Robin Williams','Frank Langella'])
RETURN m
Or:
MATCH (m:Movie)
WHERE NONE(n in ['Keanu Reeves', 'Robin Williams','Frank Langella'] WHERE (m)<-[:ACTED_IN]-(:Person {name:n}))
RETURN m
But now I would like to get movies where at maximum one of the three acted. To do that I searched for the predicate functions but I could not find a way to get the count of appearances.
How could I get movies where a percentage of given actors did not act?
You could combine NONE with SINGLE
MATCH (m:Movie)
WHERE NONE(n in ['Keanu Reeves', 'Robin Williams','Frank Langella'] WHERE (m)<-[:ACTED_IN]-(:Person {name:n}))
OR SINGLE(n in ['Keanu Reeves', 'Robin Williams','Frank Langella'] WHERE (m)<-[:ACTED_IN]-(:Person {name:n}))
RETURN m
Or you could count the pattern appearance
MATCH (m:Movie)
OPTIONAL MATCH (m)<-[:ACTED_IN]-(p:Person))
WHERE p.name in ['Keanu Reeves', 'Robin Williams','Frank Langella']
WITH m, COUNT(p) as count
WHERE count < 2
RETURN m

Neo4j Cypher Count displaying nodes, not relationships pairs Or Union Sets

My query is:
MATCH (n)-[:NT]->(p)
WHERE ...some properties filters...
RETURN n,p
The result is on the screenshot below.
How to count the total nodes?
I need 14 as a text result. Something like RETURN COUNT(n)+COUNT(p) but it shows 24.
The following request doesn't work correctly:
MATCH (n)-[:NT]->(p)
WHERE ...some properties filters...
RETURN count(n)
Returns me 12, which is the number of relationships pairs as on the picture, not nodes.
MATCH (n)-[:NT]-(p)
WHERE ...some properties filters...
RETURN count(n)
Returns 24.
How to count toward that two nodes (in this example) that have outgoing ONLY arrows? Should be 14 at once.
UPD:
MATCH (n)-[:NT]->(p)
WHERE ...
RETURN DISTINCT FILTER(x in n.myID WHERE NOT x in p.myID)
MATCH (n)-[:NT]->(p)
WHERE ...
RETURN DISTINCT FILTER(x in p.myID WHERE NOT x in n.myID)
The COUNT of DISTINCT UNION of myID gives me the result.
I don't know how to make it with cypher.
Or the DISTINCT UNION of collections:
MATCH (n)-[:NT]->(p)
WHERE ...
RETURN collect(DISTINCT p.myID), collect(DISTINCT n.myID)
The result is:
collect(DISTINCT p.myID)
26375, 26400, 21636, 29939, 20454, 26543, 19089, 4483, 26607, 30375, 26608, 26605
collect(DISTINCT n.myID)
11977, 19478, 20454
Which is 15 items. One is common. If you UNION or DISTINCT the 20454 the total COUNT would be 14. The actual number of nodes on the picture.
I can not achieve this simple pattern.
Your original queries are working correctly.
If you want to get a count of distinct n nodes, your queries should RETURN COUNT(DISTINCT n).
To count the number of nodes that only have outgoing relationships:
MATCH (n)-->()
WHERE NOT ()-->(n)
COUNT(DISTINCT n);
To count the number of distinct nodes that are directly involved in an :NT relationship:
MATCH (n)-[:NT]-()
COUNT(DISTINCT n);
MATCH (n)-[:NT]->(p)
WHERE ...some properties filters...
WITH collect(DISTINCT p.myID) AS set1
MATCH (n)-[:NT]->(p)
WHERE ...some properties filters...
WITH collect(DISTINCT n.myID) AS set2, set1
WITH set1 + set2 AS BOTH
UNWIND BOTH AS res
RETURN COUNT(DISTINCT res);

How can I use cypher to return some limited amount of nodes, and a count of all nodes?

I currently have this query:
START n=node(*)
MATCH (p:Person)-[:is_member]->(g:Group)
WHERE g.name ='FooManGroup'
RETURN p, count(p)
LIMIT 5
Say there are 42 people in FooManGroup, I want to return 5 of these people, with a count of 42.
Is this possible to do in one query?
Running this now returns 5 rows, which is fine, but a count of 104, which is the total number of nodes of any type in my DB.
Any suggestions?
You can use a WITH clause to do the counting of the persons, followed by an identical MATCH clause to do the matching of each person. Notice that you need to START on the p nodes and not just some n that will match any node in the graph:
MATCH (p:Person )-[:is_member]->(g:Group)
WHERE g.name ='FooManGroup'
WITH count(p) as personsInGroup
MATCH (p:Person)-[:is_member]->(g:Group)
WHERE g.name ='FooManGroup'
RETURN p, personsInGroup
LIMIT 5
It may not be the best or most elegant way to this, but it works. If you use cypher 2.0 it may be a bit more compact like this:
MATCH (p:Person)-[:is_member]->(g:Group {name: 'FooManGroup'})
WITH count(p) as personsInGroup
MATCH (p:Person)-[:is_member]->(g:Group {name: 'FooManGroup'})
RETURN p, personsInGroup
LIMIT 5
Relationship types are always uppercased in cypher, so :is_member should be :IS_MEMBER which I think is more readable:
MATCH (p:Person)-[:IS_MEMBER]->(g:Group {name: 'FooManGroup'})
WITH count(p) as personsInGroup
MATCH (p:Person)-[:IS_MEMBER]->(g:Group {name: 'FooManGroup'})
RETURN p, personsInGroup
LIMIT 5
Try this:
MATCH (p:Person)-[:is_member]->(g:Group)
WHERE g.name ='FooManGroup'
RETURN count(p), collect(p)[0..5]

Resources