cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Getting mutual nodes of multiple labels (more then 2)

I am having the scenario where I have multiple labels(Hashtags) and I need to get the exact mutual nodes(contributors) which are contributing on all the selected labels(Hashtags).

The Query I am using is

"WITH ["#Hashtag1","#Hashtag2","#Hashtag3"] as ids MATCH (n1:Hashtag),(n2:Hashtag) WHERE n1.id in ids and n2.id in ids and n1.id<>n2.id MATCH p = ((n1)-[*..2]-(n2)) RETURN p limit 2000"

In my use case I have 2 labels with the name (hashtag, contributor) and the relationship between them is "contributed_on".

What I want is to get all the mutual nodes of above three selected hashtags (labeled green in attached picture) in WITH clause, but from above query I am getting the data of hastag1 mutual to hashtag2 mutual, but I want only the mutual contributors(labeled pink within circle) as I highlighted in attached picture.

P.S : We may have any number of hashtags as input so I want the query to be dynamic also.

7 REPLIES 7

Could you maybe look at the intersection of results lists as described here? Also, this SO post as well as this one might help.

Well thanks,
I have tried these, but unable to get the desired result. Can you help me out to write the query.

Thanks

OK. So I created this toy graph, where I have blue nodes that I have called sources (like your green nodes) and orange nodes called targets (your pink nodes). It looks like this:

The simple way to do this query would be with something like

MATCH (n1:Source {name: 'n1'})-->(x:Target)
WITH n1, x
MATCH (n2:Source {name: 'n2'})-->(x:Target)
WITH n2, x
MATCH (n3:Source {name: 'n3'})-->(x:Target)
WITH n3, x
RETURN x.name

This totally works for this toy case where there are just 3 of your green nodes. But suppose you have way more than 3 and want this to scale. Then you could write it like this:

MATCH (n:Source) WHERE n.name in ['n1', 'n2', 'n3']
WITH collect(n) AS sourceNodes
MATCH (x:Target)
WHERE ALL (n in sourceNodes WHERE (x)<-[:CONNECTS]-(n))
RETURN x.name

In this case, you are assembling a list of those source nodes and using a predicate (ALL) to check them against.

As the graph gets larger, you will probably want to sort the source nodes in order of least connections to most so you can sift through the potential targets faster. To do this, try:

WITH ['n1', 'n2', 'n3'] AS sourceNodes
UNWIND sourceNodes AS sn
MATCH (n:Source {name:sn})
WITH n ORDER BY SIZE( (n)-[:CONNECTS]-() ) ASC
WITH collect(n) AS sources
WITH head(sources) AS first, TAIL(sources) AS rest
MATCH (first)-[:CONNECTS]->(x:Target)
WHERE ALL(n IN rest WHERE (n)-[:CONNECTS]->(x))
RETURN x.name

Please let me know if this solves the problem. Good luck!

Hi ,
I tested your created toy and its very helpful. I am so close to my desired solution but could you help me with returning the results in a graph form. Right now you are only returning "x.name" but what if I want to return all the nodes with the relation also.

Since you know that all nodes will be connected to x1, x2, and x3, returning the source node adds no value. So we could modify the query as follows:

WITH ['n1', 'n2', 'n3'] AS sourceNodes
UNWIND sourceNodes AS sn
MATCH (n:Source {name:sn})
WITH n ORDER BY SIZE( (n)-[]-() ) ASC
WITH collect(n) AS sources
WITH head(sources) AS first, TAIL(sources) AS rest
MATCH (first)-[r]->(x:Target)
WHERE ALL(n IN rest WHERE (n)-[]->(x))
RETURN r, x.name

This should return both the nodes we are interested in (x1, x2, and x3) plus the relation types between them, since we have replaced the given relationship type [:CONNECTS] with the variable [r].

Please let me know if that doesn't answer the question!

The relationship in the *Any* clause for my situation is some how like this

 
WHERE ALL(n IN rest WHERE (n)-[*..2]->(x))

.
What I really want is to make it return in the graphical form where we have all the nodes and the relationships pointed towards each other(Please see image of the original question posted)

.
As we do it in normal scenarios

`MATCH p = ((n1)-[*..2]-(n2))`
`Return p`

Some thing like this.

Maybe we are making things too complicated. Please let me know if this solves your problem:

MATCH (s:Source) WITH COUNT(s) AS num_sources 
MATCH (n:Source)-[]->(t:Target) 
WHERE SIZE(()-[]->(t)) = num_sources 
RETURN n, t