Sage Gerard
Sage Gerard

Reputation:

Tagging media with grouped tags using Neo4j and Cypher

Cypher newbie here.

I made this graph of tagged Media using the code below.

Tagged media

CREATE
(funny:Tag { name: 'Funny' }),
(sad:Tag { name: 'Sad' }),
(movie:Tag { name: 'Movie' }),
(tv:Tag { name: 'TV Show' }),
(hangover:Media { name: 'The Hangover' }),
(koth:Media { name: 'King of the Hill' }),
(simpsons:Media { name: 'The Simpsons' }),
(twm:Media { name: 'Tuesdays with Morrie' }),
(mm:Media { name: 'Mary & Max' }),
(funny)-[:DESCRIBES]->(hangover),
(funny)-[:DESCRIBES]->(koth),
(funny)-[:DESCRIBES]->(simpsons),
(sad)-[:DESCRIBES]->(twm),
(sad)-[:DESCRIBES]->(mm),
(movie)-[:DESCRIBES]->(hangover),
(movie)-[:DESCRIBES]->(twm),
(movie)-[:DESCRIBES]->(mm),
(tv)-[:DESCRIBES]->(koth),
(tv)-[:DESCRIBES]->(simpsons)

What I want to do is group Tags together into Contexts, such that one Context node has the same meaning as multiple Tags.

MATCH
(tf:Tag { name: 'Funny' }),
(tr:Tag { name: 'Sad' }),
(tm:Tag { name: 'Movie' })
(tt:Tag { name: 'TV Show' })
CREATE
(fm:Context { name: 'Funny Movies' }),
(ft:Context { name: 'Funny TV' }),
(s:Context { name: 'Sad Movies' }),
(fm)-[:INCLUDES]->(tf),
(fm)-[:INCLUDES]->(tm),
(ft)-[:INCLUDES]->(tf),
(ft)-[:INCLUDES]->(tt),
(s)-[:INCLUDES]->(tm),
(s)-[:INCLUDES]->(tr)

So now we have this thing.

With Contexts

I want to take a Context node and get Media such that ALL Tags in that Context describe each returned Media.

I tried MATCH (c:Context { name: 'Funny Movies' })-[:INCLUDES]->()-[:DESCRIBES]->(m) RETURN m to match media tagged with both Funny and Movies. The expected output was only The Hangover, but I get all Media instead.

All media

It's pretty obvious that I don't understand the kind of query I need to write. What is wrong with my query, and how can I produce the output that I want?

Upvotes: 0

Views: 139

Answers (2)

stdob--
stdob--

Reputation: 29172

You can use the bi-directional pattern:

MATCH (c:Context { name: 'Funny Movies' })-[:INCLUDES]->()-[:DESCRIBES]
      ->(m)<-
      [:DESCRIBES]-()<-[:INCLUDES]-(c)
RETURN m

Upvotes: 0

Christophe Willemsen
Christophe Willemsen

Reputation: 20185

When you start from a context, you can collect the tags and then match movies that are related to ALL the tags. The highlighted words in the previous sentence are the keywords for you as reference in the neo4j documentation :

MATCH (c:Context {name:"Funny Movies"})-[:INCLUDES]->(tag)
WITH collect(tag) AS tags
MATCH (m:Media) WHERE ALL( x IN tags WHERE (x)-[:DESCRIBES]->(m))
RETURN m

Upvotes: 2

Related Questions