karnaugh
karnaugh

Reputation: 27

Can't filter nodes on cypher query Neo4j

I've got some data, like the following:

(:Artist {id: 1, name: "Depeche Mode"})<-[:PLAYED_BY]-(:Song {id: 1, title: "Enjoy The Silence"})-[:PLAYED_BY]->(:Artist {id: 2, name: "Lacuna Coil"})

I will need to query, for example, for all the Song that are PLAYED_BY Artist with id 1 and 2.

I was thinking about something like:

MATCH (s:Song)-[:PLAYED_BY]->(a:Artist)
WHERE a.id IN [1, 2]
RETURN s

But this one is not working as I want: because it's like an OR, and I would like to use it like an AND.

Any suggestions?

EDIT1: The number of Artist should be arbitrary.

EDIT2: I will also need to run this query using a full text index, like this:

START song=node:node_auto_index("title:*enjo*") 
MATCH ... 
RETURN ...

That song is also played by other artists, for example Song 1, played by Artist [1, 2, 3]. When I query for [1,2] it should be returned anyway.

Upvotes: 2

Views: 132

Answers (2)

William Lyon
William Lyon

Reputation: 8546

So you want to find Songs that are played by both Artist 1 and Artist 2?

How about this query:

MATCH (a1:Artist)<-[:PLAYED_BY]-(s:Song)-[:PLAYED_BY]->(a2:Artist)
WHERE a1.id = 1 AND a2.id = 2
RETURN s

Edit

For an arbitrary number of Artists:

WITH [1,2] AS ids
MATCH (a:Artist)<-[:PLAYED_BY]-(s:Song)
WITH collect(a.id) AS artistIds, ids,s
WHERE all(x IN artistIds WHERE x IN ids) AND all(x IN ids WHERE x IN artistIds)
RETURN s

Collect the ids of all artists that have played the song then use the Cypher collection predicate function all to filter on only the desired Artist ids.

The array [1,2] can be parameterized like this: WITH {id_array} AS ids ...

Edit

Using a legacy index for fuzzy text search should work with this approach. Just replace the unbound (s:Song) piece of the pattern in the MATCH with the bound song variable populated by the legacy index:

START song=node:node_auto_index("title:*enjo*")
WITH [1,2] AS ids, song
MATCH (a:Artist)<-[:PLAYED_BY]-(song)
WITH collect(a.id) AS artistIds, ids, song
WHERE all(x IN artistIds WHERE x IN ids) AND all(x IN ids WHERE x IN artistIds)
RETURN s

Upvotes: 2

cybersam
cybersam

Reputation: 66957

This should work for your example:

MATCH (a1:Artist)<-[:PLAYED_BY]-(s:Song)-[:PLAYED_BY]->(a2:Artist)
WHERE a1.id = 1 AND a2.id = 2
RETURN s

Upvotes: 2

Related Questions