I have the following cql (which does not work):
MATCH p = (c2:Config)<-[:OVERRIDES*]-(c1:Config)
WHERE c1['properties.name'] = 'NodeA'
AND NOT (c2)-[:OVERRIDES]->()
UNWIND NODES(p) AS props
RETURN props.`properties.name` as name,
PROPERTIES(props) AS properties,
SIZE(nodes(p)) AS `index`
What I'm trying to do is generate an index value that either accumulates or decrements with each row. I thought maybe the number of nodes in NODES(p) would go up/down as the graph was processed, but it stays constant. Is there anyway to do what I want??
You've unwound the nodes in the path, but want to get the index of each of these nodes in the path?
You'll need to use a different approach here, as you don't get index info when you UNWIND the nodes directly. You'll need to start with the index first, and then get each node in the path via the index in the list:
...
UNWIND range(0,size(nodes(p))-1) as index
WITH p, nodes(p)[index] as props
...
Related
I have a graph of nodes with a relationship NEXT with 2 properties sequence (s) and position (p). For example:
N1-[NEXT{s:1, p:2}]-> N2-[NEXT{s:1, p:3}]-> N3-[NEXT{s:1, p:4}]-> N4
A node N might have multiple outgoing Next relationships with different property values.
Given a list of node names, e.g. [N2,N3,N4] representing a sequential path, I want to check if the graph contains the nodes and that the nodes are connected with relationship Next in order.
For example, if the list contains [N2,N3,N4], then check if there is a relationship Next between nodes N2,N3 and between N3,N4.
In addition, I want to make sure that the nodes are part of the same sequence, thus the property s is the same for each relationship Next. To ensure that the order maintained, I need to verify if the property p is incremental. Meaning, the value of p in the relationship between N2 -> N3 is 3 and the value p between N3->N4 is (3+1) = 4 and so on.
I tried using APOC to retrieve the possible paths from an initial node N using python (library: neo4jrestclient) and then process the paths manually to check if a sequence exists using the following query:
q = "MATCH (n:Node) WHERE n.name = 'N' CALL apoc.path.expandConfig(n {relationshipFilter:'NEXT>', maxLevel:4}) YIELD path RETURN path"
results = db.query(q,data_contents=True)
However, running the query took some time that I eventually stopped the query. Any ideas?
This one is a bit tough.
First, pre-match to the nodes in the path. We can use the collected nodes here to be a whitelist for nodes in the path
Assuming the start node is included in the list, a query might go like:
UNWIND $names as name
MATCH (n:Node {name:name})
WITH collect(n) as nodes
WITH nodes, nodes[0] as start, tail(nodes) as tail, size(nodes)-1 as depth
CALL apoc.path.expandConfig(start, {whitelistNodes:nodes, minLevel:depth, maxLevel:depth, relationshipFilter:'NEXT>'}) YIELD path
WHERE all(index in range(0, size(nodes)-1) WHERE nodes[index] = nodes(path)[index])
// we now have only paths with the given nodes in order
WITH path, relationships(path)[0].s as sequence
WHERE all(rel in tail(relationships(path)) WHERE rel.s = sequence)
// now each path only has relationships of common sequence
WITH path, apoc.coll.pairsMin([rel in relationships(path) | rel.p]) as pairs
WHERE all(pair in pairs WHERE pair[0] + 1 = pair[1])
RETURN path
I have a couple of nodes and I need to add a incremental value in all nodes of a particular label.
match wd= (w:MYNODE)
forEach(n IN nodes(wd)|
set n.incrementalId=??
);
currently I have tried for each to traverse on each node but unable to get index of the each loop
ps: I have also tried with but unable to increment ie ++ the current value.
This is a more succinct version of #InverseFalcon's first query (and resembles the form of the query in your question):
MATCH (w:MYNODE)
WITH COLLECT(w) as ws
FOREACH(i IN RANGE(0, SIZE(ws)-1) | SET (ws[i]).incrementalId = i);
If the nodes already exist, then you'll have to use a more awkward approach using collections and indexes:
MATCH (w:MYNODE)
WITH collect(w) as myNodes
UNWIND range(0, size(myNodes)-1) as index
WITH index, myNodes[index] as node
SET node.incrementalId = index
If the nodes don't already exist, and you want to create some number of them with incremental ids, then it's an easier task using the range() function to produce a list of indexes:
UNWIND range(1, 100) as id
CREATE (:MYNODE {id:id})
I have a graph but need to be sure that all nodes are in the path (but more than those nodes can exist in the path).
Here is an example (sorry, had to black some stuff out):
I want to find end2 and not end1 when I have the values of the same property in all three intermediary nodes in the list I pass in. But I can't get a query that will return end2 without end1. There can be more nodes out there that have the same routes but I will only every pass in distinct values that are not duplicated across the middle nodes. Anyone know of a query that will give me only the end node that has all the values from the intermediary nodes? There are also nodes that hang off of those end nodes and some of them interlink between end1 and end2. Some others do not and those are the nodes I do not want but because there is a path between the yellow and blue to that end1 I can't use ANY but because there other paths to those same nodes (not pictured) I can't use ALL either.
Thanks in advance for help.
[Update]
Here is the current query I use but it only allows for one "end" node per a start node and I want multiple. I needed that id(eg)={eg_id} passed in but that limits it to one. I would much rather use the fact that every a in the path below needs to match up to the list of name properties in the middle node must be there to get to which end node. So if yellow and blue are htere then end1 and end2 would come back but if yellow, blue and purple are there then only end2 would come back.
start td = node({td_id})
match (td:Start)-[:Rel1]->(a)<-[:Rel2]-(eg:End)-[es:Rel3]->(n:WhatsPastEnd)
with collect(a.name) as pnl, n, td, eg, es
where id(eg) = {eg_id}
and all(param_needs in {param_name_list} where param_needs in pnl)
return n
order by es.order
[SOLVED]
Thank you very much InverseFalcon, got what I need from the solution below!
Okay, let's modify your query, and drop the matching of the endnode id.
start td = node({td_id})
// unwind your list of names so every row has a name
with td, {param_name_list} as param_names
unwind param_names as param_name
match (td:Start)-[:Rel1]->(a)
where a.name = param_name
// now a has all nodes with the required names
// collect then unwind so we have the full collection for each a
with collect(a) as requiredNodes
unwind requiredNodes as a
match (a)<-[:Rel2]-(eg:End)
where all(node in requiredNodes where (node)<-[:Rel2]-(eg))
with eg
match (eg)-[es:Rel3]->(n:WhatsPastEnd)
return n
order by es.order
Neo4j: Finding simple path between two nodes takes a lot of time even after using upper limit (*1..4). I don't want to use allShortestPath or shortestPath because it doesnt return all the paths.
Match p=((n {Name:"Node1"}) -[*1..4]-> (m {Name:"Node2"})) return p;
Any suggestions to make it faster ?
If you have a lot of nodes, try creating an index so that the neo4j DB engine does not have to search through every node to find the ones with the right Name property values.
I am presuming that, in your example, the n and m nodes are really the same "type" of node. If this is true, then:
Add a label (I'll call it 'X') to every node (of the same type as n and m). You can use the following to add the 'X' label to node(s) represented by the variable n. You'd want to precede it with the appropriate MATCH clause:
SET n:X
Create an index on the Name property of nodes with the X label like this:
CREATE INDEX ON :X(Name);
Modify your query to:
MATCH p=((n:X {Name:"Node1"}) -[*1..4]-> (m:X {Name:"Node2"}))
RETURN p;
If you do the above, then your query should be faster.
I have a linked list that is modelled in a circular fashion like so:
(u:User)
-[:LINK]->(a:NODELINK {linkId: 'aa'})
-[:LINK]->(b:NODELINK {linkId: 'bb'})
-[:LINK]->(c:NODELINK {linkId: 'cc'})
-[:LINK]->(d:NODELINK {linkId: 'dd'})
-[:LINK]->(u)
When I query it starting at node (b:NODELINK {linkId: 'bb'}) I would like to match all nodes until I get to the end/start of the list. (The User node)
When I run the following query:
MATCH (u:USER)
WITH u
MATCH (nl:NODELINK)-[:LINK*]->(m)
WHERE nl.linkId = 'bb' AND m <> u
RETURN m
It returns me the following nodes
(3:NODELINK {linkId:'cc'})
(4:NODELINK {linkId:'dd'})
(1:NODELINK {linkId:'aa'})
(2:NODELINK {linkId:'bb'})
As you can see my query wraps around and starts returning nodes from the start of the list. I would like to terminate at the User node and only return the nodes before the end of the list
(3:NODELINK {linkId:'cc'})
(4:NODELINK {linkId:'dd'})
I have created a graph that demonstrates the issue here
How do I query so as to start at the node link of interest and returns all nodes before it reaches the User node?
Your WHERE clause limits the first and last node in the path, but not the intermediate ones, so yes, the query can match paths that include the user node.
Instead of matching many paths and returning only the end nodes, try matching one path from the 'cc' node to the user node, and return all nodes in that path (except the last one if you don't want the user node).
MATCH path=(nl:NODELINK {linkId:'cc'})-[:LINK*]->(u:USER)
RETURN nodes(path)
or
RETURN nodes(path)[..-1]
if you want to return all the nodes except the last one.
Try below query. I think you should bring the NODELINK where you want to begin traversing in the first MATCH clause as it will pin point your graph where to start instead of just matching user node on USER label.
MATCH (nl:NODELINK)
WHERE nl.linkId = 'aa'
WITH nl
MATCH p=(nl)-[:LINK*1..]->(m:USER)
RETURN filter(t IN nodes(p)
WHERE t <> nl) AS nodes