Skip to content
francnuec edited this page Aug 3, 2017 · 5 revisions

Here are more examples. Most of the examples on this page were copied from the Neo4jClient examples wiki page. The aim is to show how you can write same sample queries with annotations.

User class

Most of the examples below assume you have the following class, to represent the structure of a user node:

public class User
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }

    #region WithAnnotations
    [Column("FRIENDS_WITH")]
    public ICollection<User> Friends { get; set; }

    [Column("INVITED")]
    public ICollection<User> Invitees { get; set; }
    #endregion
}

Get all users by label

This Cypher:

MATCH (user:User)
RETURN user

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Return(user => user.As<User>())
    .Results

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user"))
    .Return(user => user.As<User>())
    .Results

Get specific user

This Cypher:

MATCH (user:User)
WHERE user.Id = 1234
RETURN user

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 1234)
    .Return(user => user.As<User>())
    .Results

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 1234))
    .Return(user => user.As<User>())
    .Results

Get a user, and the count of their friends

This Cypher:

OPTIONAL MATCH (user:User)-[FRIENDS_WITH]-(friend:User)
WHERE user.Id = 1234
RETURN user, count(friend) AS NumberOfFriends

Is this C#:

graphClient.Cypher
    .OptionalMatch("(user:User)-[FRIENDS_WITH]-(friend:User)")
    .Where((User user) => user.Id == 1234)
    .Return((user, friend) => new {
        User = user.As<User>(),
        NumberOfFriends = friend.Count()
    })
    .Results

With annotations:

graphClient.Cypher
    .OptionalMatch(path => path.Pattern((User user) => user.Friends, "friend")
    .Constrain(user => user.Id == 1234))
    .Return((user, friend) => new {
        User = user.As<User>(),
        NumberOfFriends = friend.Count()
    })
    .Results

Get a user, and all their friends

This Cypher:

OPTIONAL MATCH (user:User)-[FRIENDS_WITH]-(friend:User)
WHERE user.Id = 1234
RETURN user, collect(friend) AS NumberOfFriends

Is this C#:

graphClient.Cypher
    .OptionalMatch("(user:User)-[FRIENDS_WITH]-(friend:User)")
    .Where((User user) => user.Id == 1234)
    .Return((user, friend) => new {
        User = user.As<User>(),
        Friends = friend.CollectAs<User>()
    })
    .Results

With annotations:

graphClient.Cypher
    .OptionalMatch(path => path.Pattern((User user) => user.Friends, "friend")
    .Constrain(user => user.Id == 1234))
    .Return((user, friend) => new {
        User = user.As<User>(),
        Friends = friend.CollectAs<User>()
    })
    .Results

Create a user

This Cypher:

CREATE (user:User { Id: 456, Name: 'Jim' })

Should use parameters:

CREATE (user:User {newUser})

And is this C#:

var newUser = new User { Id = 456, Name = "Jim" };
graphClient.Cypher
    .Create("(user:User {newUser})")
    .WithParam("newUser", newUser)
    .ExecuteWithoutResults();

And with annotations:

var newUser = new User { Id = 456, Name = "Jim" };
graphClient.Cypher
    .Create(path => path.Pattern<User>("user")
    .Prop(() => newUser))
    .ExecuteWithoutResults();

Note that we're using an explicitly named parameter (newUser) and the query, and the WithParam method to supply it. This keeps our encoding safe, protects against Cypher-injection attacks, and improves performance by allowing query plans to be cached.

Create a user, only if they don't already exist

This Cypher:

MERGE (user:User { Id: 456 })
ON CREATE user
SET user.Name = 'Jim'

Should use parameters:

MERGE (user:User { Id: {id} })
ON CREATE user
SET user = {newUser}

And is this C#:

var newUser = new User { Id = 456, Name = "Jim" };
graphClient.Cypher
    .Merge("(user:User { Id: {id} })")
    .OnCreate()
    .Set("user = {newUser}")
    .WithParams(new {
        id = newUser.Id,
        newUser
    })
    .ExecuteWithoutResults();

And with annotations:

var newUser = new User { Id = 456, Name = "Jim" };
graphClient.Cypher
    .Merge(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 456))
    .OnCreate()
    .Set("user", () => newUser)
    .ExecuteWithoutResults();

Create a user and relate them to an existing one

This Cypher:

MATCH (inviter:User)
WHERE inviter.Id = 123
CREATE inviter-[:INVITED]->(invitee:User {newUser})

Is this C#:

var newUser = new User { Id = 456, Name = "Jim" };
graphClient.Cypher
    .Match("(inviter:User)")
    .Where((User inviter) => inviter.Id == 123)
    .Create("inviter-[:INVITED]->(invitee:User {newUser})")
    .WithParam("newUser", newUser)
    .ExecuteWithoutResults();

With annotations:

var newUser = new User { Id = 456, Name = "Jim" };
graphClient.Cypher
    .Match(path => path.Pattern<User>("inviter")
    .Constrain(inviter => inviter.Id == 123))
    .Create(path => path.Pattern((User inviter) => inviter.Invitees, "invitee")
    .Prop(null, () => newUser))
    .ExecuteWithoutResults();

Relate two existing users

This Cypher:

MATCH (user1:User), (user2:User)
WHERE user1.Id = 123, user2.Id = 456
CREATE user1-[:FRIENDS_WITH]->user2

Is this C#:

graphClient.Cypher
    .Match("(user1:User)", "(user2:User)")
    .Where((User user1) => user1.Id == 123)
    .AndWhere((User user2) => user2.Id == 456)
    .Create("user1-[:FRIENDS_WITH]->user2")
    .ExecuteWithoutResults();

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user1")
    .Constrain(user => user.Id == 123), 
    path2 => path2.Pattern<User>("user2")
    .Constrain(user => user.Id == 456))
    .Create(path => path.Pattern((User user1) => user1.Friends, "user2"))
    .ExecuteWithoutResults();

Relate two existing users, only if they aren't related already

This Cypher:

MATCH (user1:User), (user2:User)
WHERE user1.Id = 123, user2.Id = 456
CREATE UNIQUE user1-[:FRIENDS_WITH]->user2

Is this C#:

graphClient.Cypher
    .Match("(user1:User)", "(user2:User)")
    .Where((User user1) => user1.Id == 123)
    .AndWhere((User user2) => user2.Id == 456)
    .CreateUnique("user1-[:FRIENDS_WITH]->user2")
    .ExecuteWithoutResults();

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user1")
    .Constrain(user => user.Id == 123), 
    path2 => path2.Pattern<User>("user2")
    .Constrain(user => user.Id == 456))
    .CreateUnique(path => path.Pattern((User user1) => user1.Friends, "user2"))
    .ExecuteWithoutResults();

Update a single property on a user

This Cypher:

MATCH (user:User)
WHERE user.Id = 123
SET user.Age = 25

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 123)
    .Set("user.Age = {age}")
    .WithParam("age", 25)
    .ExecuteWithoutResults();

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 123))
    .Set((User user) => user.Age == 25)
    .ExecuteWithoutResults();

Note: we're using parameters again to pass in data. Never do this via string concatenation like Set("user.Age = " + age.ToString()) otherwise you will introduce encoding bugs, security risks, and significantly impact your query performance by bypassing the query plan cache in Neo4j itself.

Annotations note: If you're using Neo4jClient alone, you should abide by the preceding warning. However, if you use Neo4jClient with annotations, this library by default uses parameters for all values. You can always override this behavior by using one of the overloaded methods for the Cypher statements.

Replace all the properties on a user

This Cypher:

MATCH (user:User)
WHERE user.Id = 123
SET user = { Id: 123, Age: 25, Email: 'tatham@oddie.com.au' }

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 123)
    .Set("user = {tatham}")
    .WithParam("tatham", new User { Id = 123, Age = 25, Email = "tatham@oddie.com.au" })
    .ExecuteWithoutResults();

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 123))
    .Set("user", () => new User { Id = 123, Age = 25, Email = "tatham@oddie.com.au" })
    .ExecuteWithoutResults();

Delete a user

This Cypher:

MATCH (user:User)
WHERE user.Id = 123
DELETE user

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 123)
    .Delete("user")
    .ExecuteWithoutResults();

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 123))
    .Delete("user")
    .ExecuteWithoutResults();

Delete a user and all inbound relationships

This Cypher:

OPTIONAL MATCH (user:User)<-[r]-()
WHERE user.Id = 123
DELETE r, user

Is this C#:

graphClient.Cypher
    .OptionalMatch("(user:User)<-[r]-()")
    .Where((User user) => user.Id == 123)
    .Delete("r, user")
    .ExecuteWithoutResults();

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user", "r", null)
    .Constrain(user => user.Id == 123))
    .Delete("r, user")
    .ExecuteWithoutResults();

Get all labels for a specific user

This Cypher:

MATCH (user:User)
WHERE user.Id = 1234
RETURN labels(user)

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 1234)
    .Return(user => user.Labels())
    .Results;

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 1234))
    .Return(user => user.Labels())
    .Results;

Get all labels for a specific user, and still the user too

This Cypher:

MATCH (user:User)
WHERE user.Id = 1234
RETURN user, labels(user)

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 1234)
    .Return(user => new {
        User = user.As<User>(),
        Labels = user.Labels()
    })
    .Results

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 1234))
    .Return(user => new {
        User = user.As<User>(),
        Labels = user.Labels()
    })
    .Results;

Get a user, count their friends then add this number to the user and return.

Note: This is an example of using Neo4j 3.0 Stored Procedures. There are other ways of adding a property to an object, this is just an example of CALL and YIELD, using apoc Neo4j Stored Procedures

This Cypher:

MATCH (user:User)
WHERE user.Id = 1234
WITH user, size((user)-[:FRIENDS_WITH]->(friend)) as numberOfFriends
CALL apoc.map.setKey(user, 'numberOfFriends', numberOfFriends) YIELD value AS userWithFriends
RETURN userWithFriends

Is this C#:

graphClient.Cypher
    .Match("(user:User)")
    .Where((User user) => user.Id == 1234)
    .With("user, size((user)-[:FRIENDS_WITH]->(friend)) as numberOfFriends")
    .Call("apoc.map.setKey(user, 'numberOfFriends', numberOfFriends)")
    .Yield("value AS userWithFriends")
    .Return(userWithFriends => new {
        User = userWithFriends.As<User>()
    })
    .Results

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 1234))
    .WithPattern(out var friendsPattern, path => path.Pattern<User>((User user) => user.Friends, "friend"))
    .With($"user, size({friendsPattern}) as numberOfFriends")
    .Call("apoc.map.setKey(user, 'numberOfFriends', numberOfFriends)")
    .Yield("value AS userWithFriends")
    .Return(userWithFriends => new {
        User = userWithFriends.As<User>()
    })
    .Results

Get users of the same age as another user

This Cypher:

MATCH (user:User), (ageMate:User)
WHERE user.Id = 123, ageMate.Age = user.Age
RETURN COLLECT(ageMate) AS ageMates

Is this C#:

graphClient.Cypher
    .Match("(user:User)", "(ageMate:User)")
    .Where((User user) => user.Id == 123)
    .AndWhere((User ageMate, User user) => ageMate.Age == user.Age)
    .Return((ageMate) => new {
        AgeMates = ageMate.CollectAs<User>()
    })
    .Results;

With annotations:

graphClient.Cypher
    .Match(path => path.Pattern<User>("user")
    .Constrain(user => user.Id == 123), 
    path2 => path2.Pattern<User>("ageMate")
    .Constrain(ageMate => ageMate.Age == Vars.Get<User>("user").Age))
    .Return((ageMate) => new {
        AgeMates = ageMate.CollectAs<User>()
    })
    .Results;

Written with StackEdit.

Clone this wiki locally