Simple example of N-ary relationship to understand basics of Neo4j Graph Data Modeling
May 13: Formula 1, One Month Graph Challenge
Welcome word
In this series of small posts I do one simple graph daily. Domain model of graph somehow related to day’s history, some historical event, celebration or person. I do this challenge to learn Neo4j Data Modeling and Cypher. Every day. One month. Follow me. Maybe you will be inspired and next month would be yours One Month Graph Challenge. #OMGChallenge
Domain model
This day 69 years ago in Silverstone, England, the first race of the first Formula 1 championship took a place. And so far Formula 1 is one of the most spectacular events in the world. I remember my first childhood TV sessions when I watching Schumacher victories in Benetton team.
Today I want to analyse results of whole history of Formula 1 competition and find the best of the best pilots ever.
Let’s think a little bit about how to organize our graph. How to say that a particular pilot in a particular year won in a particular country? In the graph database language it is mean: you should to take a year node, take a country node, take a pilot node and connect them together — to get a winner node. So, winner is N-ary relationship node based on other 3 nodes. Here is the result schema:

Graph
Parse data results of Formula 1 from official website:
Winner is an aggregation root, it can includes all necessary information of these 3 nodes, so I put all three properties inside winner. Now I can say that pilot, country and year is kind of normalized nodes, while winner is kind of denormalized node. I can read only winner nodes to know everything around. Very useful for reading purposes.
One thing to add here. I got unexpected result from apoc.load.html with 2 projections. By documentation output must be a Map type with of this structure:
A: { name: <list of elements>, name2: <list of elements> }
But unfortunately, I got result of this structure:
B: [ { name: <list of elements> }, { name2: <list of elements> } ]
So, I wrote this 2 magic lines to transform A into B:
WITH collect(value) as data
WITH { pilots: data[0].pilot, places: data[1].place } as root

Now let’s find the best of the best. A person with the most victories in all history of Formula 1:

For sure, Michael Schumacher! I didn’t expect another answer. But as you can see Hamilton can do a history very soon. Write a query for this was very easy. And if you want to find the best pilots for each concrete races, it is also super simple:

Resume
Bad news: challenge appeared in the stuff, where I did not expect any problems. Good news: I got a trouble and I solve it. Level up.
Also good lesson is about a structure. N-ary relationship is a simple and powerful thing. Schema must fit you needs. Then analysis on this graph is really easy. Cheers!
Similar topics
Neo4j graph Data Modeling of Star Wars Universe with APOC load json
Initial Neo4j Graph Data Modeling of Train Ticket Booking System
Unusual use of Neo4j Common Neighbors Algorithm on people community graph
Neo4j Shortest Path and Dijkstra Algorithms
Apply Neo4j Similarity Algorithm to analyse Chess “openings”
Build a Neo4j Graph of Moscow Metro Map with Spatial Values and Shortest Path Algorithm