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.

Newbie question: How to find users which are doing multiple specific hobbies

Hi,

I’m really new to NEO4J and currently testing some simple Cypher queries.
I want to model users and their hobbies, where one user can have multiple hobbies.
Users and their hobby are created as nodes with the respective labels :User and :Hobby.

I can easily find users that are doing the hobby “Sport” or “Music”:

MATCH (u:User)-[:HAS_HOBBY]->(h:Hobby)
WHERE h.name = "Sport" OR h.name = "Music"
RETURN u

Result: Max, Joe

But how can I find users that are doing both the hobbies “Sport” AND “Music”?
In this case the query should only return the user “Max”.

Many thanks for your help.

7 REPLIES 7

Hello @drjonniex and welcome to the Neo4j community

Try:

MATCH (u:User)-[:HAS_HOBBY]->(h:Hobby)
WITH u, collect(DISTINCT h.name) AS hobbies
WHERE all(x IN hobbies WHERE x IN ["Sport", "Music"])
RETURN u

Regards,
Cobra

Many thank's for your quick and very helpful answer!

match (a:User)-[:HAS_HOBBY]->(b:Hobby)
where b.name = "Sport" 
match (a)-[:HAS_HOBBY]->(c:Hobby)
where c.name = "Music"
return a

returns Max

I expanded the example graph from above and added the additional hobby "Dancing" for "Max":

The query suggestion from @Cobra seems not work in this case

MATCH (u:User)-[:HAS_HOBBY]->(h:Hobby)
WITH u, collect(DISTINCT h.name) AS hobbies
WHERE all(x IN hobbies WHERE x IN ["Sport", "Music"])
RETURN u

Result: Joe

As i can understand the query the result seems to be logical. The hobby Sport from user Joe
satisfies

x IN hobbies WHERE x IN ["Sport", "Music"]

and because the user Joe has only one hobby the all predicate is also fulfilled.

The query suggestion from @ameyasoft works and only the user Max is returned.
But the disadvantage is that you have to use a variable name for every hobby
in the query.

I am particularly thinking about how the query can be easily and dynamically constructed when the hobby filter comes from some sort of user interface. The user can select several hobbies via a checkbox.

Hi,

MATCH (u:User)-[:HAS_HOBBY]->(h:Hobby)
WITH u, collect(DISTINCT h.name) AS hobbies
WHERE all(x IN ["Sport", "Music"] WHERE x IN hobbies)
RETURN u

Many thanks.

I would like to use the query syntax from @Cobra to combine multiple filters at once.
For example, to further narrow down the user result set by character details.

It seems to be pretty easy with the query syntax:

MATCH (u:User)-[:HAS_HOBBY]->(h:Hobby)
WITH u, collect(DISTINCT h.name) AS hobbies
WHERE all(x IN ["Sport", "Music"] WHERE x IN hobbies)

WITH u
MATCH (u)-[:HAS_CHARACTER]->(c:CharacterDetail)
WITH u, collect(DISTINCT c.name) AS cdetails
WHERE all(x IN ["Calm", "Spontaneous"] WHERE x IN cdetails)

WITH U
*** NEXT FILTER ***

WITH U
*** NEXT FILTER ***

RETURN u

Are there any performance considerations by applying multiple filters at once
on databases with a large amount of user nodes?

As I understand it would be necessary to create an index on the name property for the
Hobby and CharacterDetail nodes.

Normally, indexes are useful when they are directly specified in the WHERE clause, for example: n.id = 0. In your case, you already collected the name for each nodes so I don't think there will be any improvments but you can still try

Documentation

You could also use subquery with UNION