Starting with Neo4j, I am pretty sure, this question could be even stupid because the solution might be so easy. But I am not sure how to solve this, I want to combine two queries:
First I search for nodes, which are all themselves parent nodes:
MATCH (parentnodes:DemoMenue) WHERE (parentnodes)-[:IS_PARENT_OF]-> () RETURN parentnodes
Then I want do get the endNodes for each of the matched parentnodes above. If just doing it with one specified parentnode it would for example work like this:
MATCH (x:DemoMenue {title: "A2"})-[r]-() RETURN endNode(r)
Now what is the suggested way/technique in Cypher to apply my second query to each of the matching parentnodes of my first query?
Your two queries can be merged into one without using a foreach loop:
MATCH (parentnodes:DemoMenue)-[r:IS_PARENT_OF]-> () RETURN endNode(r)
If you want to do something for each result in a collection, you can use Foreach, but keep in mind that you can only use SET in foreach, not return.
And to complete my answer, your query is not 'returning' any collection, so you can't use foreach on it, you'll have to use collect before
Why don't you just use:
MATCH (parentnodes:DemoMenue)-[:IS_PARENT_OF]-> (endNode)
RETURN endNodes
Related
I need 2 lists of nodes for the call of my procedure. The following query doesnt work because the first list is not defined (overwritten with the second collect I guess). I already tried a lot of queries but somehow im missing the right one. I think this one is showing what I actually want to achieve.
MATCH (n:NODE)
WHERE n.NODE_ELID='BLOCK1' OR n.NODE_ELID='BLOCK2'
WITH COLLECT(n) AS blockNodes
MATCH (m:NODE)
WHERE m.NODE_ELID='MUST1' OR m.NODE_ELID='MUST2'
WITH COLLECT(m) AS mustNodes
MATCH (from:NODE{NODE_ELID:'START'}),(to:NODE{NODE_ELID:'END'})
CALL example.aStar(from,to,'CONNECTED_TO','DISTANCE','COORD_X','COORD_Y',blockNodes,mustNodes) yield path as path, weight as weight
RETURN path, weight
Thanks in advance.
Pass along blockNodes in line 6:
WITH blockNodes, COLLECT(m) AS mustNodes
The point here is that WITH does many things: it performs projection, aggregation, filtering (as WITH clauses can have their own WHERE clause) and ordering/limiting. See the docs on WITH for more details.
Anyone know of a fast way to query multiple paths in Neo4j ?
Lets say I have movie nodes that can have a type that I want to match (this is psuedo-code)
MATCH
(m:Movie)<-[:TYPE]-(g:Genre { name:'action' })
OR
(m:Movie)<-[:TYPE]-(x:Genre)<-[:G_TYPE*1..3]-(g:Genre { name:'action' })
(m)-[:SUBGENRE]->(sg:SubGenre {name: 'comedy'})
OR
(m)-[:SUBGENRE]->(x)<-[:SUB_TYPE*1..3]-(sg:SubGenre {name: 'comedy'})
The problem is, the first "m:Movie" nodes to be matched must match one of the paths specified, and the second SubGenre is depenedent on the first match.
I can make a query that works using MATCH and WHERE, but its really slow (30 seconds with a small 20MB dataset).
The problem is, I don't know how to OR match in Neo4j with other OR matches hanging off of the first results.
If I use WHERE, then I have to declare all the nodes used in any of the statements, in the initial MATCH which makes the query slow (since you cannot introduce new nodes in a WHERE)
Anyone know an elegant way to solve this ?? Thanks !
You can try a variable length path with a minimal length of 0:
MATCH
(m:Movie)<-[:TYPE|:SUBGENRE*0..4]-(g)
WHERE g:Genre and g.name = 'action' OR g:SubGenre and g.name='comedy'
For the query to use an index to find your genre / subgenre I recommend a UNION query though.
MATCH
(m:Movie)<-[:TYPE*0..4]-(g:Genre { name:'action' })
RETURN distinct m
UNION
(m:Movie)-[:SUBGENRE]->(x)<-[:SUB_TYPE*1..3]-(sg:SubGenre {name: 'comedy'})
RETURN distinct m
Perhaps the OPTIONAL MATCH clause might help here. OPTIONAL MATCH beavior is similar to the MATCH statement, except that instead of an all-or-none pattern matching approach, any elements of the pattern that do not match the pattern specific in the statement are bound to null.
For example, to match on a movie, its genre and a possible sub-genre:
OPTIONAL MATCH (m:Movie)-[:IS_GENRE]->(g:Genre)<-[:IS_SUBGENRE]-(sub:Genre)
WHERE m.title = "The Matrix"
RETURN m, g, sub
This will return the movie node, the genre node and if it exists, the sub-genre. If there is no sub-genre then it will return null for sub. You can use variable length paths as you have above as well with OPTIONAL MATCH.
[EDITED]
The following MATCH clause should be equivalent to your pseudocode. There is also a USING INDEX clause that assumes you have first created an index on :SubGenre(name), for efficiency. (You could use an index on :Genre(name) instead, if Genre nodes are more numerous than SubGenre nodes.)
MATCH
(m:Movie)<-[:TYPE*0..4]-(g:Genre { name:'action' }),
(m)-[:SUBGENRE]->()<-[:SUB_TYPE*0..3]-(sg:SubGenre { name: 'comedy' })
USING INDEX sg:SubGenre(name)
Here is a console that shows the results for some sample data.
I am doing the following Cypher query:
MATCH (a) WHERE a.itemId IN ['Q2', 'Q24', 'Q30', 'Q23', 'Q16', 'Q20'] RETURN a
I'd like it to return the same results as when I set the Auto-Complete switch. This question was asked and answered 1 but I don't understand the answer. Can this be performed in one query, and if so, what would the modified query be?
Yeah, you should be able to do it all in one query. To get the nodes in question along with their relationships you can do:
MATCH (a)
WHERE a.itemId IN ['Q2', 'Q24', 'Q30', 'Q23', 'Q16', 'Q20']
OPTIONAL MATCH (a)-[rel]-()
RETURN a, collect(rel)
That will return you, for each node, an array of the relationships.
Depending on your library that you're using for Neo4j, that may or may not return you something useful to give you the startnode/endnode. You could also do:
MATCH (a)
WHERE a.itemId IN ['Q2', 'Q24', 'Q30', 'Q23', 'Q16', 'Q20']
OPTIONAL MATCH (a)-[rel]-()
RETURN a, collect({rel: rel, start_node: startNode(rel), end_node: endNode(rel)})
That would give you an array for each node containing objects/maps of the data.
Got some separate clarification on the question about how to only return the relationships between the nodes that are matched. This should be possible like so:
MATCH (a)
WHERE a.itemId IN {itemIds}
OPTIONAL MATCH (a)-[rel]-(b)
WHERE b.itemId IN {itemIds}
RETURN a, collect(rel)
Again, you also might want to return the startNode/endNode of the relationships
Single relationships can be excluded by types using
Match (n:Person)-[r]-(m:Person) where type(r)<>"FRIENDS" return n,r,m
Is there a way to exclude multilevel relationships with cypher?
Match (n:Person)-[r*2..4]-(h:Hobby) where type(r)<>"FRIENDS" return n,r,h
Sure, you can do that. Like this:
Match (n:Person)-[r*2..4]-(h:Hobby)
where NONE( rel in r WHERE type(rel)="FRIENDS")
return n,r,h
Your query doesn't work because with multi-level paths, your r is a collection of relationships rather than a single one. So you can use any of the predicates on collections to do the filtering that you want.
Here, I chose NONE with type(rel)=FRIENDS, which means that you'll only get the result back if NONE of the relationships are of type FRIENDS. But you might instead want to use ANY or ALL, depending on what your query is supposed to mean.
Anyway, the main point here is to use a predicate function to turn a collection of things into a single boolean value.
You can use the ALL or ANY predicates for this:
MATCH p=(n:Person)-[*2..4]-(h:Hobby)
WHERE ALL(x in relationships(p) WHERE type(x) <> "FRIENDS")
RETURN n,r,h
Use the ALL predicate to make sure every relationship along that path is not a FRIEND. Use ANY to make sure you have at least one relationship not being FRIEND.
I have a query that takes too long to execute:
MATCH (s:Person{id:"103"}), s-[rel]-a WITH rel, s
MATCH c1-[:friend]->s<-[:friend]-c2, c1-[fol:follows]->c2
RETURN DISTINCT c1,c2;
However, when I split it in two:
MATCH (s:Person{id:"103"}), s-[rel]-a
RETURN rel, s;
and
MATCH (s:Person{id:"103"}),
c1-[:friend]->s<-[:friend]-c2, c1-[fol:follows]->c2
RETURN DISTINCT c1,c2;
they are much faster.
Why is it that passing rel and s to the next query makes it so much slower?
(I'm asking because that sample query is only a part of a bigger one and I pass on rel and s with the WITH instead of RETURN to the next part of the query)
Thank you
The first cycles for each node and relation found in the first MATCH:
MATCH (s:Person{id:"103"}), s-[rel]-a WITH rel, s
One row for each relation involving that node. I would use the third query, since rel is never used.
Maybe you try to "profile" the query in Neo4J console, it will give you some clues of how the query actually executed in server.
btw, why would you need to pass the on the "rel" since it never been used