Get middle node between two node neo4j - neo4j

I need to find common node between two nodes. For example find B from A -> B -> C
A = node 1
B = node 2
C = node 3
A, B and C have common property (user_id, fullname) and relation property is KNOWS. node index is user_id.
Node related to:
A [:KNOWS] B and B [:KNOWS] C
I have A and C node id. I want find B node id. How can I do this using Cypher or neo4jphp?

Would really prefer to see something that you had written yourself, but I suppose sometimes that's just too much effort...
START a=node(1)
MATCH (a)-[:KNOWS]->(b)-[:KNOWS]->(c)
WHERE a.user_id = ... (Explanation on what exactly should be done here was lacking)
RETURN b

Related

Neo4j - Find missing node to complete circle

I am trying to get a query that starting from a node, it returns the missing node that, when making a new relation to it, would complete a circle. Also it should respond which is the node that, if the circle is close, will end up having a relationship with the input node. Example:
Let's say I have B -> C and C -> A. In this case, if I pass A as input, I would like to receive { newRelationToMake: B, relationToInputNode: C } as a result, since connecting A -> B will result in a closed circle ABC and the relation that the node A will be having will come from C.
Ideally, this query should work for a maximum of n depths. For example for a depth of 4, with relations B -> C, C -> D and D -> A, and I pass A as input, I would need to receive { newRelationToMake: C, relationToInputNode: D} (since if I connect A -> C I close the ACD circle) but also receive {newRelationToMake: B, relationToInputNode: D }(since if I connect A -> B I would close the ABCD circle).
Is there any query to get this information?
Thanks in advance!
You are basically asking for all distinct nodes on paths leading to A, but which are not directly connected to A.
Here is one approach (assuming the nodes all have a Foo label and the relationships all have the BAR type):
MATCH (f:Foo)-[:BAR*2..]->(a:Foo)
WHERE a.id = 'A' AND NOT EXISTS((f)-[:BAR]->(a))
RETURN DISTINCT f AS missingNodes
The variable-length relationship pattern [:BAR*2..] looks for all paths of length 2 or more.

neo4j Cypher -- traverse variable length path, but stop when a label is found

Suppose my graph database has a 'flow' of foo nodes. in between each foo nodes might be any number of bar, bar1, bar2, ...barN nodes which ultimately connect to the next foo node.
So, all of these are possible
(a:foo)-->(:bar)-->(b:foo)
(b:foo)-->(:bar)-->(c:foo)-->(:bar1)-->(d:foo)
(a:foo)-->(:bar)-->(:bar1)-->(:bar2)-->(:barN)-->(c:foo)
etc.
I'd like to return each distinct pair of foo nodes which do NOT have any other foo nodes between them
For the above examples, the solution should return:
a, b
b, c
c, d
a, c
Solution should NOT include the following, which have foo nodes between them:
b, d
a, d
What I've tried. this returns all foo pairs that connect, regardless of what's in between.
MATCH x=(a:foo)-[:RELTYPE*1..]->(b:foo)
RETURN a,b
This should work:
MATCH x = (a:foo)-[:RELTYPE*..]->(b:foo)
WHERE NONE(n IN NODES(x)[1..-1] WHERE ANY(l IN LABELS(n) WHERE l = 'foo'))
RETURN a, b
[UPDATE]
Or even better:
MATCH x = (a:foo)-[:RELTYPE*..]->(b:foo)
WHERE NONE(n IN NODES(x)[1..-1] WHERE n:foo)
RETURN a, b
You can also leverage APOC Procedures for path expansion procs which can handle this kind of use case.
Using this graph:
CREATE (a:foo {name:'a'}), (b:foo {name:'b'}), (c:foo {name:'c'}), (d:foo {name:'d'}),
(a)-[:RELTYPE]->(:bar)-[:RELTYPE]->(b),
(b)-[:RELTYPE]->(:bar)-[:RELTYPE]->(c)-[:RELTYPE]->(:bar1)-[:RELTYPE]->(d),
(a)-[:RELTYPE]->(:bar)-[:RELTYPE]->(:bar1)-[:RELTYPE]->(:bar2)-[:RELTYPE]->(:barN)-[:RELTYPE]->(c)
We can apply this query:
MATCH (start:foo)
CALL apoc.path.subgraphNodes(start, {relationshipFilter:'RELTYPE>', labelFilter:'/foo'}) YIELD node as end
RETURN start, end
This starts at every :foo node, traverses only outgoing :RELTYPE relationships, and will terminate expansion when reaching a :foo labeled node (the / before the 'foo' in the label filter indicates that this is a termination filter on the label).

Neo4j - Intersect two node lists using Cypher

Having the following graphs:
node g1 with child nodes (a, b)
node g2 with child nodes (b, c)
using the query
MATCH (n)-[]-(m) WHERE ID(m) = id RETURN n
being id the id of the node g1, I get a and b, and vice-versa when using the id of g2. What I would like to understand is how can I get the intersection of those two results, in this case having the first return (a, b) and the second return (b, c) getting as final result (b).
I tried using the WITH cause but I wasn't able to achieve the desired result. Keep in mind that I'm new to Neo4j and only came here after a few failed attempts, research on Neo4j Documentation, general google search and
Stackoverflow.
Edit1 (one of my tries):
MATCH (n)-[]->(m)
WHERE ID(m) = 750
WITH n
MATCH (o)-[]->(b)
WHERE ID(b) = 684 and o = n
RETURN o
Edit2:
The node (b), that I represented as being the same on both graphs are in fact two different nodes on the db, each one relating to a different graph (g1 and g2). Representatively they are the same as they have the exactly same info (labels and attributes), but on the database thy are not. I'm sorry since it was my fault for not being more explicit on this matter :(
Edit3:
Why I don't using a single node (b) for both graphs
Using the graphs above as example, imagine that I have yet another layer so: on g1 the child node (b) as a child (e), while on g2 the child node (b) as a child (f). If I had (b) as a single node, when I create (e) and (f) I only could add it to (b) loosing the hierarchy, becoming impossible to distinguish which of them, (e) or (f), belonged to g1 ou g2.
This should work (assuming you pass id1 and id2 as parameters):
MATCH (a)--(n)--(c)
WHERE ID(a) = {id1} AND ID(c) = {id2}
RETURN n;
[UPDATED, based on new info from comments]
If you have multiple "clones" of the "same" node and you want to quickly determine which clones are related without having to perform a lot of (slow) property comparisons, you can add a relationship (say, typed ":CLONE") between clones. That way, a query like this would work:
MATCH (a)--(m)-[:CLONE]-(n)--(c)
WHERE ID(a) = {id1} AND ID(c) = {id2}
RETURN m, n;
You can find the duplicity of the node, by using this query -
[1]
Duplicity with single node -
MATCH pathx =(n)-[:Relationship]-(find) WHERE find.name = "action" RETURN pathx;
[2]
or for two nodes giving only immediate parent node
MATCH pathx =(n)-[:Relationship]-(find), pathy= (p)-[:Relationship]
-(seek) WHERE find.name = "action" AND seek.name="requestID" RETURN pathx,
pathy;
[3]
or to find the entire network i.e. all the nodes connected -
MATCH pathx =(n)--()-[:Relationship]-(find), pathy= (p)--()-[:Relationship]-
(seek) WHERE find.name = "action"
AND seek.name="requestID" RETURN pathx, pathy;

Find the path beween two nodes even middle node is missing graph query

I would like to find path between two nodes like
[:relation] [:relation] [:relation]
A-------------B--------------C------------D
(name=A) (name=B) (name=C) (name=D)
So, I have only A B D and want to find A B C D
I tried
MATCH
(q1:check4 {name:'A'})-[r1:relation]->
(q2:check4 {name:'B'})-[r2:relation]->(q3:check4 {name:'D'})
RETURN DISTINCT q3.name as name
But it's not working.
If you are trying to find the name attribute of the node between B and D, this query should do it:
MATCH
(:check4 {name:'A'})-[:relation]->
(:check4 {name:'B'})-[:relation]->
(q3:check4)-[:relation]->
(:check4 {name:'D'})
RETURN DISTINCT q3.name as name
A tip: you do not have to name every node and relationship, e.g. q1, r1 can be omitted.

How to move the properties and relationships of one node to another?

I have two separate nodes in the graph, and at one point I will get a signal that those two nodes should actually be one. So I have to merge the two including their properties (there's no overlap) AND I should maintain the relationships as well.
Example graph: (d)->(a {id:1}), (b)->(c {name:"Sam"})
Desired result: (d)->(a {id:1, name:"Sam"}), (b)->(a {id:1, name:"Sam"})
The label a doesn't have to be the case really in the result - the point is we will have only one node representing the original two.
The following merges the properties fine.
MATCH (a:Entity {id:"1"}), (c:Entity {name:"Sam"})
SET a += c
But I can't seem to find a way to move/copy the relationships.
The specs:
The two nodes won't have the same properties
node a may have incoming and outgoing relationships
node c may have incoming relationships, non outgoing
Any thoughts?
Update:
The following works, assuming the type and properties coming to node c are known in advance. Can I improve this to make it more dynamic?
MATCH (a:Entity {id1:"1"}), (c:Entity {id2:"2"})
SET a += c
WITH a, c
MATCH (c)<-[r]-(b)
WITH a, c, r, b
MERGE (b)-[:REL_NAME {prop1:r.prop1, prop2:r.prop2}]->(a)
WITH c
DETACH DELETE c
Update 2:
The above throws unable to load relationship with id error sometimes and I'm not sure why, but it seems it's related to reading/writing at the same time.
Update 3:
This is a work around for the error:
MATCH (a:Entity {id1:"1"}), (c:Entity {id2:"2"})
SET a += c
WITH a, c
MATCH (c)<-[r]-(b)
WITH a, c, r, b
MERGE (b)-[r2:REL_NAME]->(a)
SET r2 += r
WITH r, c
DELETE r, c
The problem when moving relationships between nodes is that you can't set the relationship type dynamically.
So you can't MATCH all relationships from node c and recreate them on node a. This does not work:
MATCH (a:Entity {id1:"1"}), (c:Entity {id2:"2"})
WITH a, c
// get rels from node c
MATCH (c)-[r]-(b)
WITH a, c, r, b
// create the same rel from node a
MERGE (b)-["r.rel_type" {prop1:r.prop1, prop2:r.prop2}]->(a)
With neo4j 3 there are so called procedures which are plugins for the server and can be called from Cypher queries. The apoc procedure package provides procedures that do what you need: https://neo4j-contrib.github.io/neo4j-apoc-procedures/
First install the apoc plugin on your server, then use something like:
// create relationships with dynamic types
CALL apoc.create.relationship(person1,'KNOWS',{key:value,…​}, person2)
// merge nodes
CALL apoc.refactor.mergeNodes([node1,node2])

Resources