Neo4j - Cypher node and relationship relation - neo4j

I have the following query:
MATCH (dg:DecisionGroup)-[:CONTAINS]->(childD:Decision)
WHERE dg.id = {decisionGroupId}
MATCH (filterCharacteristic1:Characteristic)
WHERE filterCharacteristic1.id = 1
WITH dg, filterCharacteristic1
CALL apoc.index.between(childD,'HAS_VALUE_ON',filterCharacteristic1,'(value:(10))') YIELD rel
WITH DISTINCT rel, childD, dg
MATCH (childD)-(rel) // here I need to go further only with 'childD' nodes that have relationship with 'rel'(match `apoc.index.between` predicate)
As you may see from the query above - at the end I'm trying to filter childD nodes that have the relationship with rel but I don't know how to describe it in Cypher. Something like (childD)-(rel) or (childD)-[rel] doesn't work and leads to the error. Please help

You need to look for a match pattern and compare the relationship:
...
WITH DISTINCT rel, childD, dg
MATCH (childD)-[tmp]-() WHERE tmp = rel
RETURN rel, child, dg
Or you can compare directly:
...
WITH DISTINCT rel, childD, dg, startNode(rel) AS sRel, endNode(rel) AS eRel
WHERE (childD)--(sRel) OR (childD)--(eRel)
RETURN rel, child, dg

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 query null or IN

I have a following cypher query:
MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User)
WHERE id(parentD) = {decisionId}
RETURN ru, u, childD
SKIP 0 LIMIT 100
Decision entity can belong to 0..N Tenant objects
#NodeEntity
public class Decision {
private final static String BELONGS_TO = "BELONGS_TO";
#Relationship(type = BELONGS_TO, direction = Relationship.OUTGOING)
private Set<Tenant> tenants = new HashSet<>();
....
}
I need to extend the Cypher query above in order to return all childD where parentD and childD not belong to any of Tenant or belong to Tenant with IDs provided in {tenantIds} set. Please help me with this query.
Cypher is very expressive language, just follow your textual requirements...
MATCH (t:Tenant) WHERE ID(t) in {tenantIds}
WITH COLLECT(t) as tenants
MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User)
WHERE
id(parentD) = {decisionId}
AND
// not belong to any of Tenant or belong to Tenant
(not (parentD)-[:BELONGS_TO]-(:Tenant) OR any(t in tenants WHERE (parentD)-[:BELONGS_TO]-(t)))
AND
// not belong to any of Tenant or belong to Tenant
(not (childD)-[:BELONGS_TO]-(:Tenant) OR any(t in tenants WHERE (childD)-[:BELONGS_TO]-(t)))
RETURN ru, u, childD
SKIP 0 LIMIT 100
Use optional match to collect and test tenants:
MATCH (parentD) WHERE id(parentD) = {decisionId}
OPTIONAL MATCH (parentD)-[:BELONGS_TO]->(T:Tenant)
WHERE NOT id(T) IN {tenantIds}
WITH parentD, collect(T) AS TC
WHERE size(TC) <= 0
MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User)
OPTIONAL MATCH (childD)-[:BELONGS_TO]->(T:Tenant)
WHERE NOT id(T) IN {tenantIds}
WITH childD, ru, u, collect(T) AS TC
WHERE size(TC) <= 0
RETURN ru, u, childD
SKIP 0 LIMIT 100

Cypher to find similar nodes without repeating matches

I am new to cypher. I want to find similar nodes without repeating matches.
Sample data
CREATE (r1:Repository {id:"repository1"})
CREATE (r2:Repository {id:"repository2"})
CREATE (r3:Repository {id:"repository3"})
CREATE (a1:Actor {id: "actor1"})
CREATE (a2:Actor {id: "actor2"})
CREATE (a3:Actor {id: "actor3"})
CREATE (o1:Organization {id:"organization1"})
CREATE (o2:Organization {id:"organization2"})
MATCH (a:Repository {id:"repository1"}) MATCH (b:Actor {id: 'actor1'})
CREATE (a)-[:IS_ACTOR]->(b)
MATCH (a:Repository {id:"repository1"}) MATCH (b:Actor {id: 'actor2'})
CREATE (a)-[:IS_ACTOR]->(b)
MATCH (a:Repository {id:"repository1"}) MATCH (b:Actor {id: 'actor3'})
CREATE (a)-[:IS_ACTOR]->(b)
MATCH (a:Repository {id:"repository1"}) MATCH (b:Organization {id:
'organization1'}) CREATE (a)-[:IN_ORGANIZATION]->(b)
MATCH (a:Repository {id:"repository2"}) MATCH (b:Actor {id: 'actor1'})
CREATE (a)-[:IS_ACTOR]->(b)
MATCH (a:Repository {id:"repository2"}) MATCH (b:Actor {id: 'actor2'})
CREATE (a)-[:IS_ACTOR]->(b)
MATCH (a:Repository {id:"repository2"}) MATCH (b:Organization {id:
'organization1'}) CREATE (a)-[:IN_ORGANIZATION]->(b)
MATCH (a:Repository {id:"repository3"}) MATCH (b:Actor {id: 'actor3'})
CREATE (a)-[:IS_ACTOR]->(b)
MATCH (a:Repository {id:"repository3"}) MATCH (b:Organization {id:
'organization2'}) CREATE (a)-[:IN_ORGANIZATION]->(b)
Cypher
MATCH (a)-[r1:IS_ACTOR|IN_ORGANIZATION]->(match)<-
[r2:IS_ACTOR|IN_ORGANIZATION]-(b)
where not a.id = b.id with a,b,count(match) as count, collect (match.id) as
connections, collect (type(r1)) as rel1
return a.id,b.id,count,connections,rel1 order by count desc
Result
a.id b.id count connections rel1
repository2 repository1 3 actor1,actor2,organization1 IS_ACTOR, IS_ACTOR,IN_ORGANIZATION
repository1 repository2 3 actor1,actor2,organization1 IS_ACTOR, IS_ACTOR,IN_ORGANIZATION
repository3 repository1 1 actor3 IS_ACTOR
repository1 repository3 1 actor3 IS_ACTOR
How can I remove row #2 & #4 from the result?
Based on response to a similar question I tried using filter but I get syntax error (cypher below)
MATCH (a)-[r1:IS_ACTOR|IN_ORGANIZATION]->(match)<-
[r2:IS_ACTOR|IN_ORGANIZATION]-(b)
with filter(x in connections where x <> b.id)
where not a.id = b.id with a,b,count(match) as count, collect (match.id) as
connections, collect (type(r1)) as rel1
return a.id,b.id,count,connections,rel1 order by count desc
You match the path once from both sides, something that you can do to force only one of those paths to be returned. Compare the id's so you put a and b in a fixed order and avoid the other combo.
MATCH (a)-[r1:IS_ACTOR|IN_ORGANIZATION]->(match)
<-[r2:IS_ACTOR|IN_ORGANIZATION]-(b)
where id(a) > id(b)
with a,b,count(match) as count,
collect (match.id) as connections, collect (type(r1)) as rel1
return a.id,b.id,count,connections,rel1 order by count desc

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