Home > database >  (n)->(on)<-(n) cypher query gives me a cartesian product
(n)->(on)<-(n) cypher query gives me a cartesian product

Time:05-11

I have a Cypher query that goes something like this:

MATCH (t1:Team)-[:PLAYS_ON]->(m:Match)<-[:PLAYS_ON]-(t2:Team)
RETURN t1 AS "Team 1", m AS "Match", t2 as "Team 2"

My goal is to have a query that allows me to see matches and which teams are matching eachother in a deportive context.

Assuming Team 1, Team 2 and Team 3, and the matches being Team 1 vs Team 2 and Team 2 vs Team 3, my expected output is:

 ------ ----- ------ 
|Team 1|match|Team 2|
|------ ----- ------|
|Team 1|date |Team 2|
|Team 2|date |Team 3|
 ------ ----- ------ 

But I get:

 ------ ----- ------ 
|Team 1|match|Team 2|
|------ ----- ------|
|Team 1|date |Team 2|
|Team 2|date |Team 1|
|Team 2|date |Team 3|
|Team 3|date |Team 2|
 ------ ----- ------ 

I'm relatively new to Cypher/Neo4J, so, I would not be impressed if it turns out i'm commiting a very obvious and stupid mistake, but I don't have the brains to see it.

Thank you for your answers!

CodePudding user response:

One way to do it is:

MATCH (t:Team)-[:PLAYS_ON]->(m:Match)
WITH collect(t) AS t, m
RETURN t[0] AS t1, m, t[1] AS t2

Which on this sample data:

MERGE (a:Team{name: 'Team1'})
MERGE (b:Team{name: 'Team2'})
MERGE (c:Team{name: 'Team3'})
MERGE (d:Match{Date: '2022-05-11'})
MERGE (e:Match{Date: '2022-05-12'})

MERGE (a)-[:PLAYS_ON]-(d)
MERGE (b)-[:PLAYS_ON]-(d)
MERGE (b)-[:PLAYS_ON]-(e)
MERGE (c)-[:PLAYS_ON]-(e)

Will give you this:

╒════════════════╤═════════════════════╤════════════════╕
│"t1"            │"m"                  │"t2"            │
╞════════════════╪═════════════════════╪════════════════╡
│{"name":"Team1"}│{"Date":"2022-05-11"}│{"name":"Team2"}│
├────────────────┼─────────────────────┼────────────────┤
│{"name":"Team2"}│{"Date":"2022-05-12"}│{"name":"Team3"}│
└────────────────┴─────────────────────┴────────────────┘

In order to understand this solution, you can read about the concept of cardinality.

Basically, since the number of options for the first MATCH is two per each (:Match) (two teams, one match) the query will return two options per each (:Match). Since you want only one results per match, you can use collect to group these two lines into one.

In other words, your query is saying get all options for this arrangement, meaning two per match. The query here is getting all options per match and then "group by" match, to create a list of teams per each match.

  • Related