match in clause in cypher - neo4j

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?

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;

Neo4j Cypher relationship existis and collection of IDs

I have a following Neo4j Cypher query that checks if relationship exists between User and entity and returns boolean result:
MATCH (u:User) WHERE u.id = {userId} MATCH (entity) WHERE id(entity) = {entityGraphId} RETURN EXISTS( (u)<-[:OWNED_BY]-(entity) )
Please help to rewrite this query in order to be able to accept a collection of {entityGraphIds} instead of a single {entityGraphId} and check if a relationship exists between User and any entities with these {entityGraphIds}.
For example, I have user1 and entity1, entity2. user1 has a relationship with entity2. I'll pass {user.id} like {userId} and {entity1.id, entity2.id} like {entityGraphIds} and this query should return true.
I believe you can simply use the IN operator. Considering these parameters:
:params {userId: 1, entityGraphIds : [2,3,4]}
Then, the query:
MATCH (u:User) WHERE u.id = {userId}
MATCH (entity) WHERE id(entity) IN ({entityGraphIds})
RETURN EXISTS( (u)<-[:OWNED_BY]-(entity) )
EDIT:
If you are trying to return true when :User is connected to at least 1 entity, then you can simplify your query to:
OPTIONAL MATCH (u:User)<-[:OWNED_BY]-(entity:Entity)
WHERE u.id = {userId} AND id(entity) IN ({entityGraphIds})
RETURN u IS NOT NULL

neo4j pass parameter to variable length relationship

How do I use parameters with variable length relationships?
MATCH path=(:Person {id: {id}})=[:HAS_FRIEND*0..{num_friends}]->(:Person)
I'm trying to create a generic query so that I can pass a value 'num_friends' into the cypher query for various levels of relationships that I need.
I get an error so I'm wondering how something like this would be done?
Parameters can not be used as hops count.
But you can use path expander from apoc:
match (P:Person {id: {id}}) with P
call apoc.path.expand( P, 'HAS_FRIEND>', 'Person', 0, {num_friends}) yield path
return path
Adapted for comment:
match (P:Person {id: {id}}) with P
call apoc.path.expand( P, 'HAS_FRIEND>', 'Person', 0, {num_friends}) yield path
with path, last(nodes(path)) as lst where not (lst)-[:HAS_FRIEND]->(:Person)
return path

Optional nodes in a path?

I'm trying to write a query where I get the :LIKES relationships.
(:USER)
|
[:CREATED]
|
(:POST)<-[:LIKES]-(:USER)
|
[:RESHARED]
|
(:POST)<-[:LIKES]-(:USER)
I was trying something along the lines of:
MATCH (u:USER {name: "Lamoni"})-[:CREATED]-(p:POST)
OPTIONAL MATCH p<-[:LIKES]-(u2:USER)
OPTIONAL MATCH p<-[:RESHARED]-(p2:POST)<-[:LIKES]-(u3:USER)
Any ideas on an optimal way to do this and be able to order them by a property called created_at in a descending order?
Thanks!
If the POST structure always looks like this you can try:
// match the whole user-post-post path
MATCH (u:USER {name: "Lamoni"})-[:CREATED]-(p_direct:POST)-[:RESHARED]-(p_shared:Post)
WITH u, p_direct, p_shared
OPTIONAL MATCH (p_direct)<-[:LIKES]-(u2:USER)
OPTIONAL MATCH (p_shared)<-[:LIKES]-(u3:USER)
RETURN u.name, p_direct.xyz, collect(u2.name), p_shared.xyz, collect(u3.name)
If you just want all USERS that like a POST by a given USER (independent of the type of POST, created or shared) you can also collect all POST:
MATCH (u:USER {name: "Lamoni"})-[:CREATED|RESHARED*1..2]-(p:Post)
WITH u, p
OPTIONAL MATCH (p)<-[:LIKES]-(u2:USER)
WITH u.name, p, u2
ORDER BY u2.created_at
RETURN u.name, p, collect(u2.name)

Resources