Nishant Srivastava
Nishant Srivastava

Reputation: 379

How to get nodes that are realted to more than one node which in turn are related to more than one node in Neo4j using Cypher

I am a newbie in neo4j and no doubt i am loving it.

Now my query is i have a database in which there are users who have visited one or more than one urls and these urls contain one or more than one tags.

Now what i want is to retrieve tags for a certain user who has visited more than one urls.

the relation is somewhat like this:

(:User)-[:VISITED]->(:URL)-[:CONTAINS]->(:Tag)

Now i want to retrieve user who has visited more than one urls and all the tags contained in all those urls. So basically i want all the tags that a user has visited where visited urls are more than one.

Upvotes: 2

Views: 87

Answers (2)

Mik378
Mik378

Reputation: 22171

Using Cypher 2.X, this should make the job:

MATCH (user:User)
MATCH user-[:VISITED]->(url:URL)
WITH count(url) AS countUrl, url
WHERE countUrl > 1
MATCH url-[:CONTAINS]->(tag:Tag)
RETURN user.id, collect(tag) AS tags //you can show whatever you want here

Upvotes: 3

Christophe Willemsen
Christophe Willemsen

Reputation: 20185

You can still optimize the query provided by Mik378.

In fact, in Cypher you can reproduce the java equivalent of getDegree with the size(pattern) clause :

MATCH (n:User)-[:VISITED]->(url)<-[:TAGS]-(tag:Tag)
WHERE size((n)-[:VISITED]->()) > 1
RETURN n.email, collect(distinct tag.name) as tags

which would result in the following query plan :

+------------------+---------------+------+--------+------------------------------------------+----------------------------------------------------+
|         Operator | EstimatedRows | Rows | DbHits |                              Identifiers |                                              Other |
+------------------+---------------+------+--------+------------------------------------------+----------------------------------------------------+
| EagerAggregation |             3 |    5 |     90 |                            n.email, tags |                                            n.email |
|       Projection |             7 |   24 |     48 | anon[15], anon[37], n, n.email, tag, url |                                       n.email; tag |
|        Filter(0) |             7 |   24 |     24 |          anon[15], anon[37], n, tag, url |                                            tag:Tag |
|   Expand(All)(0) |             7 |   24 |     34 |          anon[15], anon[37], n, tag, url |                               (url)<-[:TAGS]-(tag) |
|        Filter(1) |             3 |   10 |     10 |                         anon[15], n, url |                                            url:Url |
|   Expand(All)(1) |             3 |   10 |     15 |                         anon[15], n, url |                              (n)-[:VISITED]->(url) |
|        Filter(2) |             2 |    5 |     10 |                                        n | GetDegree(n,Some(VISITED),OUTGOING) > {  AUTOINT0} |
|  NodeByLabelScan |             5 |    5 |      6 |                                        n |                                              :User |
+------------------+---------------+------+--------+------------------------------------------+----------------------------------------------------+

Total database accesses: 237

The query was with my test db, so for your current implementation, it should be :

MATCH (n:User)-[:VISITED]->(url)-[:CONTAINS]->(tag:Tag)
WHERE size((n)-[:VISITED]->()) > 1
RETURN n.email, collect(distinct tag.name) as tags

Upvotes: 3

Related Questions