Search code examples
c#neo4jneo4jclient

How to check if a relation exists between two nodes using .net client of neo4j


I have a role based application and 2 nodes Role and Cartable and i am managing my permissions by creating a relation between these 2 nodes, if a relationship exists between these two nodes means this role has a permission for example to view the Cartable:

client.Cypher

            .Merge("(s:SiteConfiguration)-[:" 
            + Relations.ROLE_IN_SITE.ToString()+ "]-(r:Role)-[r1:"
            + Relations.ROLE_HAS_CARTABLE.ToString() + "]->(ca:Cartable)")
            .Where("r.Id = {param}").WithParam("param", roleId)
            .AndWhere("ca.Id= {param1}").WithParam("param1", cartableId)
            .AndWhere("s.SiteId= {param2}").WithParam("param2", MvcApplication.SiteConfigurations.Base.SiteId)
            .CreateUnique("(r)-[:" + Relations.EDIT_COMMENT.ToString()+"]-(ca)")
            .ExecuteWithoutResults();

Now i want to check if relation exists between two nodes and return a Boolean based on that so i wrote this:

var q = new CypherFluentQuery(client) as ICypherFluentQuery;

q = q.Match("(s:SiteConfiguration)-[:" 
    + Relations.ROLE_IN_SITE.ToString() + "]-(r:Role)-[r1:" 
    + Relations.VIEW_CARTABLE.ToString() + "]-(c:Cartable)");
q = q.Where("s.SiteId= {param}").WithParam("param", MvcApplication.SiteConfigurations.Base.SiteId);
q = q.AndWhere("r.Id= {param1}").WithParam("param1", roleId);
q = q.AndWhere("c.Id= {param2}").WithParam("param2", cartableId);

But I'm not sure what i should return here, since VIEW_CARTABLE doesn't have any values as anonymous object on the relationship. so my question is how to check if a certain relationship exists between these two nodes?


Solution

  • Because you are using a MATCH - you won't get any results if r1 is not there. If you know you're going to get (s)-->(r) - but not sure about (r)-->(c) then you need to go OPTIONAL.

    For example (using the :play Movies db):

    var query = gc.Cypher
        .Match("(p:Person {name:'Julia Roberts'})")
        .OptionalMatch("(p)-[r]->(m:Movie)")
        .Where("m.title = 'The Green Mile'")
        .Return((p, m) => new
        {
            Person = p.As<Person>(),
            Movie = m.As<Movie>(),
            IsInMovie = Return.As<bool>("NOT (r IS NULL)")
        });
    

    Here I look for a person (Julia Roberts) and then try to see if she has a relationship to a given movie - in this case to one I know she's not in.

    I use an OptionalMatch to do this, and then check if r is null.

    Now, in practice - I don't need to know about r, as if there is no link to the movie, m will be null.

    In your case, you'd switch the top to be:

    var q = new CypherFluentQuery(client)
        .Match("(s:SiteConfiguration)-[:ROLE_IN_SITE]-(r:Role)")
        .OptionalMatch("(r)-[r1:VIEW_CARTABLE]-(c:Cartable)")
        .Where("s.SiteId= {param}").WithParam("param", MvcApplication.SiteConfigurations.Base.SiteId)
        .AndWhere("r.Id= {param1}").WithParam("param1", roleId)
        .AndWhere("c.Id= {param2}").WithParam("param2", cartableId)
        .Return((s,r,c,r1) => new {
            Site = s.As<SiteConfiguration>(),
            Role = r.As<Role>(),
            Cartable = c.As<Cartable>(),
            IsCartable = Return.As<bool>("NOT (r1 IS NULL)")
            });
    

    And you can either check if IsCartable is true or if Cartable == null