Search code examples
c#regexneo4jneo4jclient

c# neo4j cypher use regular exp


I'm using the Neo4j graph DB with Neo4jClient and I'm trying to execute a search query on nodes, where the result should return a list of nodes that contain a given query string.

I have this working, but it seems inefficient as I'm bringing all the Groups back and then filtering. Is there a better way?

    internal object SearchGroups(string query)
    {
        var groups = WebApiConfig.GraphClient.Cypher
            .Match("(g:Groups)")
            .Return(g => g.As<Groups>())
            .Results;
        List<Groups> groupList = new List<Groups>();
        foreach (var item in groups)
        {
            if (item.GroupName.Contains(query))
            {
                groupList.Add(item);
            }
        }
        return groupList;
    }

I've seen examples that filter using .Where((Groups g)=> g.GroupName == query) but this only returns if it matches, not if it Contains.


Solution

  • Well, you're mostly there with the tag of regex - you have 2 options depending on what you want to do, and what your query is. First though - Please read the documentation for Cypher and try your queries out in the Admin window (localhost:7474) first, you'll find it hugely beneficial. In particular for this the Where documentation would have helped you a lot.

    Option 1: Regex

    var groups = WebApiConfig.GraphClient.Cypher
        .Match("(g:Groups)")
        .Where("g.GroupName =~ {nameParam}")
        .WithParam("nameParam", string.Format(".*{0}.*", query))
        .Return(g => g.As<Groups>())
        .Results;
    

    Cypher for this looks like:

    MATCH (g:Groups) WHERE g.GroupName =~ '.*<your query text>.*' RETURN g
    

    This is using a regex - as a parameter which will work in the same way as Contains. Using regex like this is not performant, and it might be better if you can do something like....

    Option 2: Starts With

    This is only applicable if you're using Neo4j 2.3+ and your query is a Starts With type query, but would be significantly faster.

    var groups = WebApiConfig.GraphClient.Cypher
        .Match("(g:Groups)")
        .Where((Groups g) => g.GroupName.StartsWith(query))
        .Return(g => g.As<Groups>())
        .Results;
    

    Cypher for this looks like:

    MATCH (g:Groups) WHERE g.GroupName STARTS WITH <your query text> RETURN g
    

    PS

    You really should return IEnumerable<Groups>/ICollection<Groups>/IList<Groups> from your method instead of object, and you could also replace your foreach with:

    var groupsList = groups.Where(g => g.GroupName.Contains(query)).ToList();
    

    Or just return it:

    return groups.Where(/*see above*/);