Creating new relationships from path (neo4j) - neo4j

I try to build a new relationship from the allshortpath returned path.
$
MATCH (p1:Category {catName: "Main_topic_classifications"}),
(p2:Category {catName: "Monarchs_of_the_Bulgars"}),
path = allShortestPaths((p2)-[:SUBCAT_OF*]->(p1))
FOREACH (s IN rels(path) |
MERGE (startNode(s))-[:NEW_SUBCAT]->(ENDNODE(s)))
However, when I run this previous query I obtained this error:
Neo.ClientError.Statement.SyntaxError: Invalid input '(': expected an identifier character, whitespace, NodeLabel, a property map or ')' (line 5, column 24 (offset: 248))
" MERGE (:startNode(s))-[:NEW_REL]->(:ENDNODE(s)))"
^

The Cypher language does not allow a node pattern to contain a function that returns the node (even though that would be very convenient).
This query (which first creates the node variables s and e, so that they can be used in node patterns) should work for you:
MATCH
(p1:Category {catName: "Main_topic_classifications"}),
(p2:Category {catName: "Monarchs_of_the_Bulgars"}),
path = allShortestPaths((p2)-[:SUBCAT_OF*]->(p1))
UNWIND RELATIONSHIPS(path) AS rel
WITH STARTNODE(rel) AS s, ENDNODE(rel) AS e
MERGE (s)-[:NEW_SUBCAT]->(e)

Related

What is the latest method to get all nodes and its relationship path using patterns in neo4j

I'm executing the below query in neo4j which returns me all the nodes along with its relationship paths
Query
MATCH (p:MyNode {name : "Vivek"})-[r*1..2]->(f:MyNode) return p,[x in r | type(x)] as rel,f
Result
{vivek} ["knows"] {Rajesh}
{vivek} ["knows","friendof] {Ezhil}
While this query executes right and gives me expected results i get the below warning in the neo4j browser
Binding relationships to a list in a variable length pattern is
deprecated. (Binding a variable length relationship pattern to a
variable ('r') is deprecated and will be unsupported in a future
version. The recommended way is to bind the whole path to a variable,
then extract the relationships: MATCH p = (...)-[...]-(...) WITH *,
relationships(p) AS r)
Just to upgrade my query i've tried variety of ways but nothing helped. Looking for help on this aspect.
Here is a matching combination i've tried as suggested in the help
MATCH p1 = (p:MyNode {name : "Vivek"})-[r*1..2]-(f:MyNode) WITH *, relationships(p1) AS r return p1
Result
Multiple result columns with the same name are not supported (line 1,
column 60 (offset: 59)) "MATCH p1 = (p:MyNode {name :
"Vivek"})-[r*1..2]-(f:MyNode) WITH *, relationships(p1) AS r return
p1"
Update
MATCH p1 = (p:MyNode {name : "Vivek"})-[r*1..2]-(f:MyNode)
WITH *, relationships(p1) AS r return p1
when you did * in the second line, you are taking all the columns generated in first list and they are p1,p,r,f . That is why you cannot alias relationships(p1) as r again.
To get the results as in query-1. you can do like this-
MATCH path=(p:MyNode {name : "Vivek"})-[r*1..2]->(f:MyNode)
return p,[x in relationships(path) | type(x)] as rel,f

Put a query into a foreach

I want to use the returned shortest path between each node and the root (Main topic classification) to build my graph. I use the following query
MATCH ()-[:SUBJECT]->(c:Category)
UNWIND NODES(c) AS nd // to get all the nodes on which I want to iterate
FOREACH(n in nd|
WITH n as start
path = allShortestPaths((start)-[:SUBCAT_OF*]-> (p1:Category {catName: "Main_topic_classifications"}))
UNWIND RELATIONSHIPS(path) AS rel
WITH STARTNODE(rel) AS s, ENDNODE(rel) AS e
MERGE (s)-[:NEW_SUBCAT]->(e)
)
For each node c, I try to compute all shortest paths to reach the root and than I use the returned path result to create a newrelationships (NEW_SUBCAT). However, when I run the previous query, I get the follwoing error:
Neo.ClientError.Statement.SyntaxError: Invalid input '(': expected an identifier character, whitespace, NodeLabel, a property map or ')' (line 5, ...)
This simpler query may do what you want (FOREACH is totally unnecessary):
MATCH (start:Category)
WHERE ()-[:SUBJECT]->(start)
MATCH path = allShortestPaths((start)-[:SUBCAT_OF*]-> (p1:Category {catName: "Main_topic_classifications"}))
UNWIND RELATIONSHIPS(path) AS rel
WITH STARTNODE(rel) AS s, ENDNODE(rel) AS e
MERGE (s)-[:NEW_SUBCAT]->(e)

cypher query to return or keep only the final sequence when variable length relationship identifiers are used

Is there a way to keep or return only the final full sequences of nodes instead of all subpaths when variable length identifiers are used in order to do further operations on each of the final full sequence path.
MATCH path = (S:Person)-[rels:NEXT*]->(E:Person)................
eg: find all sequences of nodes with their names in the given list , say ['graph','server','db'] with same 'seqid' property exists in the relationship in between.
i.e.
(graph)->(server)-(db) with same seqid :1
(graph)->(db)->(server) with same seqid :1 //there can be another matching
sequence with same seqid
(graph)->(db)->(server) with same seqid :2
Is there a way to keep only the final sequence of nodes say ' (graph)->(server)->(db)' for each sequences instead of each of the subpath of a large sequence like (graph)->(server) or (server)->(db)
pls help me to solve this.........
(I am using neo4j 2.3.6 community edition via java api in embedded mode..)
What we could really use here is a longestSequences() function that would do exactly what you want it to do, expand the pattern such that a and b would always be matched to start and end points in the sequence such that the pattern is not a subset of any other matched pattern.
I created a feature request on neo4j for exactly this: https://github.com/neo4j/neo4j/issues/7760
And until that gets implemented, we'll have to make do with some alternate approach. I think what we'll have to do is add additional matching to restrict a and b to start and end nodes of full sequences.
Here's my proposed query:
WITH ['graph', 'server' ,'db'] as names
MATCH p=(a)-[rels:NEXT*]->(b)
WHERE ALL(n in nodes(p) WHERE n.name in names)
AND ALL( r in rels WHERE rels[0]['seqid'] = r.seqid )
WITH names, p, a, rels, b
// check if b is a subsequence node instead of an end node
OPTIONAL MATCH (b)-[rel:NEXT]->(c)
WHERE c.name in names
AND rel.seqid = rels[0]['seqid']
// remove any existing matches where b is a subsequence node
WITH names, p, a, rels, b, c
WHERE c IS NULL
WITH names, p, a, rels, b
// check if a is a subsequence node instead of a start node
OPTIONAL MATCH (d)-[rel:NEXT]->(a)
WHERE d.name in names
AND rel.seqid = rels[0]['seqid']
// remove any existing matches where a is a subsequence node
WITH p, a, b, d
WHERE d IS NULL
RETURN p, a as startNode, b as endNode
MATCH (S:Person)-[r:NEXT]->(:Person)
// Possible starting node
WHERE NOT ( (:Person)-[:NEXT {seqid: r.seqid}]->(S) )
WITH S,
// Collect all possible values of `seqid`
collect (distinct r.seqid) as seqids
UNWIND seqids as seqid
// Possible terminal node
MATCH (:Person)-[r:NEXT {seqid: seqid}]->(E:Person)
WHERE NOT ( (E)-[:NEXT {seqid: seqid}]->(:Person) )
WITH S,
seqid,
collect(distinct E) as ES
UNWIND ES as E
MATCH path = (S)-[rels:NEXT* {seqid: seqid}]->(E)
RETURN S,
seqid,
path
[EDITED]
This query might do what you want:
MATCH (p1:Person)-[rel:NEXT]->(:Person)
WHERE NOT (:Person)-[:NEXT {seqid: rel.seqid}]->(p1)
WITH DISTINCT p1, rel.seqid AS seqid
MATCH path = (p1)-[:NEXT* {seqid: seqid}]->(p2:Person)
WHERE NOT (p2)-[:NEXT {seqid: seqid}]->(:Person)
RETURN path;
It first identifies all Person nodes (p1) with at least one outgoing NEXT relationship that have no incoming NEXT relationships (with the same seqid), and their distinct outgoing seqid values. Then it finds all "complete" paths (i.e., paths whose start and end nodes have no incoming or outgoing NEXT relationships with the desired seqid, respectively) starting at each p1 node and having relationships all sharing the same seqid. Finally, it returns each complete path.
If you just want to get the name property of all the Person nodes in each path, try this query (with a different RETURN clause):
MATCH (p1:Person)-[rel:NEXT]->(:Person)
WHERE NOT (:Person)-[:NEXT {seqid: rel.seqid}]->(p1)
WITH DISTINCT p1, rel.seqid AS seqid
MATCH path = (p1)-[:NEXT* {seqid: seqid}]->(p2:Person)
WHERE NOT (p2)-[:NEXT {seqid: seqid}]->(:Person)
RETURN EXTRACT(n IN NODES(path) | n.name);

how to remove Neo4j nodes with duplicate properties?

In Neo4j 2.1.6, I have nodes that are non-unique in respect of a certain property, inputID.
Using Cypher, how do I remove all nodes that are duplicates in terms of a given property, leaving only uniques?
I have tried the following...
MATCH (n:Input)
WITH n.inputID, collect(n) AS nodes
WHERE size(nodes) > 1
FOREACH (n in tail(nodes) | DELETE n)
...but it results in...
Expression in WITH must be aliased (use AS) (line 2, column 6)
"WITH n.inputID, collect(n) AS nodes"
^
Thanks,
G
You're not aliasing that WITH variable. Change this:
WITH n.inputID, collect(n) AS nodes
To this:
WITH n.inputID AS inputID, collect(n) AS nodes
As you correctly found out, using tail on a collection will let you remove the duplicates, don't forget to remove relationships before the node (DETACH) and alias the field as FrobberOfBits mentioned:
MATCH (n:Input)
WITH n.inputID AS inputID, collect(n) AS nodes
WHERE size(nodes) > 1
FOREACH (n in tail(nodes) | DETACH DELETE n)

neo4j collecting nodes and relations type b-->a<--c,a<--d

I am extending maxdemarzi's excellent graph visualisation example (http://maxdemarzi.com/2013/07/03/the-last-mile/) using VivaGraph backed by neo4j.
I want to display relationships of the type
a-->b<--c,b<--d
I tried the query
MATCH p = (a)--(b:X)--(c),(b:X)--(d)
RETURN EXTRACT(n in nodes(p) | {id:ID(n), name:COALESCE(n.name, n.title, ID(n)), type:LABELS(n)}) AS nodes,
EXTRACT(r in relationships(p)| {source:ID(startNode(r)) , target:ID(endNode(r))}) AS rels
It looks like the named query picks up only a-->b<--c pattern and omits the b<--d patterns.
Am i missing something... can i not add multiple patterns in a named query?
The most immediate problem is that the comma in the MATCH clause separates the first pattern from the second. The variable 'p' only stores the first pattern. This is why you aren't getting the results you desire. Independent of that, you are at risk of having a 'loose binding' by putting a label on both of your nodes named 'b' in the two patterns. The second 'b' node should not have a label.
So here is a version of your query that should work.
MATCH p1=(a)-->(b:X)<--(c), p2=(b)<--(d)
WITH nodes(p1) + d AS ns, relationships(p1) + relationships(p2) AS rs
RETURN EXTRACT(n IN ns | {id:ID(n), name:COALESCE(n.name, n.title, ID(n)), type:LABELS(n)}) AS nodes,
EXTRACT(r in rs| {source:ID(startNode(r)) , target:ID(endNode(r))}) AS rels
Capture both paths, then build collections from the nodes and relationships of both paths. The collection of nodes actually only extracts the nodes from p1 and adds the 'd' node. You could write that part as
nodes(p1) + nodes(p2) as ns
but then the 'b' node will appear in the list twice.

Resources