There’s an excellent post by Sergey Tihon about using Neo4j with F#, written back in March, before Neo4j began the progression into Cypher 2.0. (Gist for this here: https://gist.github.com/cskardon/7673426)
Some of the benefits of the newer Neo4jClient versions are the general move away from using Node / NodeReferences and going for a more consistent Cypher only approach, so I’ve updated the code by Sergey to use the 2.0 stuff (as part of the process of answering this StackOverflow question).
BTW: It should be noted, I am not an F# developer, so any corrections are warmly received!
I’m using VS2013 and I’ve created a new FSharp Console Application for this, which I believe is a different approach to Sergey, but I think you can do the same ‘script’ approach he has, but with this code (below) and we’ll be cooking.
Sergey is creating a basic twitter pattern, so Person A follows Person B etc, we need a POCO for our person:
[<CLIMutable>]
type Person = { Name:string; Twitter:string }
Now we can define our new ‘createPerson’ function:
let createPerson person =
client.Cypher
.Create("(p:Person {param})")
.WithParam("param", person)
.Return<Person>("p")
.Results
.Single()
Here we’ve attached a ‘Person’ label to our person being created.
So, let’s create some people:
let pA = createPerson { Name = "PersonA"; Twitter = "tA" }
let pB = createPerson { Name = "PersonB"; Twitter = "tB" }
let pC = createPerson { Name = "PersonC"; Twitter = "tC" }
let pD = createPerson { Name = "PersonD"; Twitter = "tD" }
Now, we need to add the ‘follows’ function:
let follows target source =
client.Cypher
.Match("(s:Person)", "(t:Person)")
.Where(fun s -> s.Twitter = source.Twitter)
.AndWhere(fun t -> t.Twitter = target.Twitter)
.CreateUnique("s-[:follows]->t")
.ExecuteWithoutResults()
Again, we’re using the Labels in the Match clause, CreateUnique will only create the link if it doesn’t already exist, which is what we’re after. So once again, following Sergey’s example, let’s do some following:
pB |> follows pA
pC |> follows pA
pD |> follows pB
pD |> follows pC
We now have a graph like so:

In the next step Sergey adds a ‘knows’ relationship, with some data defining ‘how’ the people know each other. So step one, let’s create our Knows data:
[<CLIMutable>]
type Knows = { How:string }
Note, there is no use of the ‘Relationship’ classes here, we’re shifting away from them. Now we need to define our knows function, I’ve modified the function signature here to allow us to use Parameters which is better for Neo4j on the whole, plus we don’t really want a load of ‘Knows’ relationships with different data structures.
let knows target (details : Knows) source =
client.Cypher
.Match("(s:Person)", "(t:Person)")
.Where(fun s -> s.Twitter = source.Twitter)
.AndWhere(fun t -> t.Twitter = target.Twitter)
.CreateUnique("s-[:knows {knowsData}]->t")
.WithParam("knowsData", details)
.ExecuteWithoutResults()
And let’s make B know C…
pB |> knows pC {How = "colleagues"}
Now we can do the same query as Sergey and get all the people who follow ‘A’:
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return<Person>("e")
.Results
.Select(fun x -> x.Name)
As I said before, I’m not au fait with F# really, there are a couple of things I’d have liked to have done, but I’m not sure how at the moment, the biggest (and most annoying) is the Return statements. They should be:
.Return(fun p -> p.As<Person>())
But the F# compiler complains about that, so I’ve had to drop back to the
.Return<Person>("p")
route. Maybe someone can figure out how to get that to work, which would be awesome!