Neo4j cypher ALL IN - neo4j

I have the following Cypher query:
MATCH (genre:Genre)<-[:BELONGS_TO]-(t:Title)
WHERE genre.name IN ["Comedy", "Drama"]
RETURN t
Which returns titles that belong to Comedy OR Drama genres.
How to change this query in order to return all titles that belong to Comedy AND Drama genres?

SIZE is your friend.
MATCH (t:Title)-[:BELONGS_TO]->(g:Gender)
WHERE g.name IN ["Comedy", "Drama"]
WITH t, COLLECT(g) AS g
WHERE SIZE(g) >= x
RETURN t
x - is number of elements in IN clause

Related

Neo4j Match with multiple relationships

I need a MATCH where either relationship is true. I understand the (person1)-[:r1|:r2]-(person2). The problem I am having is that one of the MATCH traverse through another node. IE:
(p1:person)-[:FRIEND]-(p2:person)-[:FRIEND]-(p3:person)
So I want this kind of logic. The enemy of my enemy is my friend. And my friend is my friend. Output list of all the names who are my friend. I also limit the relationship to a particular value.
Something like:
MATCH (p1:Person)-[:ENEMY{type:'human'}]-(myEnemy:Person)-[enemy2:ENEMY{type:'human'}]-(myFriend:Person)
OR (p1:Person)-[friend:FRIEND{type:'human'}]-(myFriend:Person)
RETURN p1.name, myFriend.name
I need one list that I can then do aggregation on.
This is my first posting....so if my question is a mess...hit me with your feedback and I will clarify :)
You can use the UNION clause to combine 2 queries and also remove duplicate results:
MATCH (p:Person)-[:ENEMY{type:'human'}]-(:Person)-[:ENEMY{type:'human'}]-(f:Person)
WHERE ID(p) < ID(f)
RETURN p.name AS pName, f.name AS fName
UNION
MATCH (p:Person)-[:FRIEND{type:'human'}]-(f:Person)
WHERE ID(p) < ID(f)
RETURN p.name AS pName, f.name AS fName
The ID(p) < ID(f) filtering is done to avoid having the same pair of Person names being returned twice (in reverse order).
[UPDATE]
To get a count of how many friends each Person has, you can take advantage of the new CALL subquery syntax (in neo4j 4.0) to do post-union processing:
CALL {
MATCH (p:Person)-[:ENEMY{type:'human'}]-(:Person)-[:ENEMY{type:'human'}]-(f:Person)
WHERE ID(p) < ID(f)
RETURN p.name AS pName, f
UNION
MATCH (p:Person)-[:FRIEND{type:'human'}]-(f:Person)
WHERE ID(p) < ID(f)
RETURN p.name AS pName, f
}
RETURN pName, COUNT(f) AS friendCount

(Neo4j, Cypher) How to set incremental number to relationships?

i'm using neo4j. what i'd like to do is to create a root node for search result and to create relationships from root node to search result nodes. and I'd like to set incremental number to each relationship's property.
if possible, with one query.
Sorry for not explaining enough.
This is what I'd like to do.
Any more concise way?
// create test data
WITH RANGE(0, 99) AS indexes,
['Paul', 'Bley', 'Bill', 'Evans', 'Robert', 'Glasper', 'Chihiro', 'Yamanaka', 'Fred', 'Hersch'] AS names
UNWIND indexes AS index
CREATE (p:Person { index: index, name: (names[index%10] + toString(index)) });
// create 'Results' node with relationships to search result 'Person' nodes.
// 'SEARCH_RESULT' relationships have 'order' and 'orderBy' properties.
CREATE(x:Results{ts: TIMESTAMP()})
WITH x
MATCH(p:Person)
WHERE p.name contains '1'
MERGE(x)-[r:SEARCH_RESULT]->(p)
WITH x, r, p
MATCH (x)-[r]->(p)
WITH x, r, p
ORDER BY p.name desc
WITH RANGE(0, COUNT(r)-1) AS indexes, COLLECT(r) AS rels
UNWIND indexes AS i
SET (rels[i]).order = i
SET (rels[i]).orderBy = 'name'
RETURN rels;
// validate
MATCH(x:Results)-[r:SEARCH_RESULT]->(p:Person)
RETURN r, p.name ORDER BY r.order;

Displaying Relationships in Neo4j

I wrote a CQL, and i am getting the result in the tabular format, now i want to show it graphically.
Here is the code in CQL:
match (tc:TeamCoaches)-[:BELONGS_TO]->(t:Teams)
with t.TeamName as TeamNames,
count(distinct tc.CoachName) as no_of_coach,
collect (tc.CoachName) as Coachnames
where no_of_coach>= 2
return TeamNames, no_of_coach,Coachnames
Actual Results:
TeamNames no_of_coach Coachnames
A 2 [P,Q]
B 3 [X,Y,Z]
Expected Results: Should be in graphical form.
Example:
(P)------------->(A)<---------------(Q)
BELONGS_TO BELONGS_TO
BELONGS_TO BELONGS_TO
(X)------------->(B)<--------------->(Y)
^
|
|BELONGS_TO
|
(Z)
You need to return nodes instead of their properties(here you are returning names) to show in the graph form.
You can modify your query to show in graph form as :
MATCH (tc:TeamCoaches)-[:BELONGS_TO]->(t:Teams)
WITH t, count(distinct tc) as no_of_coach
WHERE no_of_coach>= 2
MATCH P=(tc:TeamCoaches)-[:BELONGS_TO]->(t)
RETURN P

Cypher Neo4j ORDER BY DESC query

I want to order the COUNT(Movie.title) in descending order.
But it gives an error.
This is the query.
MATCH (Movie {genre:"Action"})<-[:ACTS_IN]-(Person)
"RETURN Person.name, Movie.genre, COUNT(Movie.title)"
"ORDER BY COUNT(Movie.title) DESC"
"LIMIT 100";
Thanks!
You can use this query:
MATCH (movie:Movie {genre:"Action"})<-[:ACTS_IN]-(person:Person)
RETURN person.name, movie.genre, COUNT(distinct movie.title) AS cnt
ORDER BY cnt DESC
LIMIT 100
The error is returned because you cannot order by an aggregate immediately in Cypher. To order by any aggregate you need to use the WITH operator.
So your query should be (assumes that you want to list the titles per actor per genre):
MATCH (Movie {genre:"Action"})<-[:ACTS_IN]-(Person)
RETURN Person.name, Movie.genre, COUNT(Movie.title)
WITH Person.name AS name, Movie.genre AS genre, COLLECT(Movie.title) AS titles
RETURN name, genre, titles
ORDER BY LENGTH(titles) DESC
LIMIT 100
The limit 100 has now changed its behaviour so you probably want to move it up into the query:
MATCH (Movie {genre:"Action"})<-[:ACTS_IN]-(Person)
RETURN Person.name, Movie.genre, COUNT(Movie.title)
WITH Person, Movie
LIMIT 100
WITH Person.name AS name, Movie.genre AS genre, COLLECT(Movie.title) AS titles
RETURN name, genre, titles
ORDER BY LENGTH(titles) DESC
Aside: to make your queries perform well you should have an Index on the Movie.genre property and you should introduce labels for Movie and Person.

match in clause in cypher

How can I do an match in clause in cypher
e.g. I'd like to find movies with ids 1, 2, or 3.
match (m:movie {movie_id:("1","2","3")}) return m
if you were going against an auto index the syntax was
START n=node:node_auto_index('movie_id:("123", "456", "789")')
how is this different against a match clause
The idea is that you can do:
MATCH (m:movie)
WHERE m.movie_id in ["1", "2", "3"]
However, this will not use the index as of 2.0.1. This is a missing feature in the new label indexes that I hope will be resolved soon. https://github.com/neo4j/neo4j/issues/861
I've found a (somewhat ugly) temporary workaround for this.
The following query doesn't make use of an index on Person(name):
match (p:Person)... where p.name in ['JOHN', 'BOB'] return ...;
So one option is to repeat the entire query n times:
match (p:Person)... where p.name = 'JOHN' return ...
union
match (p:Person)... where p.name = 'BOB' return ...
If this is undesirable then another option is to repeat just a small query for the id n times:
match (p:Person) where p.name ='JOHN' return id(p)
union
match (p:Person) where p.name ='BOB' return id(p);
and then perform a second query using the results of the first:
match (p:Person)... where id(p) in [8,16,75,7] return ...;
Is there a way to combine these into a single query? Can a union be nested inside another query?

Resources