1
votes

I know this may sound nonsense but I will try my best to explain the problem that I am facing with neo4jClient.

I developing a Social TaskManagment Software. and for the server side code and data Storage I choose to have neo4j (neo4jClient) and C# in place.

in Our software Imagine a User : (mhs) Post a Task of "@somebody please help me on #Neo4j #cypher" the task would be decorated with some fancy character including (@ # + /) the obove post will be save in neo4j as graph like this :

(post:Post {Text : @somebody please help me on #Neo4j})-[Has_HashTag]-(neo4j:HashTag)
(post:Post)-[Has_HashTag]-(Cypher: HashTag)
(post:Post)-[Has_Author)-[mhs:User]
(post:Post)-[Has_MentionedUser)-[Somebody:User]

Now Imagine User @mhs is trying to search the Post that Have HashTag of #Neo4j and mentioned to @somebody

Here I am building (hand Craft) a Cypher Query Including the 2 seach Paramerts in Cypher with Some Fancy C# code which result the blow Cypher Query:

MATCH (nodes)-[r]-(post:Post),
(post:Post)-[:HAS_MentionedUsers]->(assignee1307989068:User),
(nodes)-[r]-(post:Post)-[:HAS_HashTags]->(Hashtag1482870844:HashTag)
WHERE (assignee1307989068.UserName = "somebody") AND (Hashtag1482870844.Value = "neo4j")
RETURN post AS Post, Collect(nodes) as nodes
ORDER BY post.creationDate

the above cypher will return a post with just all the nodes of the post that is not included in Where clause. my question is how to include all the Nodes related to the Targeted (post) without including them in Return part of the cypher. Something like return (*).

The Other problem is How can I deserialize the result set into C# without knowing what shape it may have.

The Search method that I am producing the mentioned Cypher is as fallow:

public List<PostNode> Search(string searchterm)
    {
        List<string> where = new List<string>();
        var tokenizedstring = searchterm.Split(' ');
        var querystring = new StringBuilder();
        var relatedNodes = new List<string>();

        var q = new CypherFluentQuery(_graphClient) as ICypherFluentQuery;

        foreach (var t in tokenizedstring)
        {
            _commandService.BuildPostQueystring(t, ref querystring, ref where, ref relatedNodes);
        }
        if (querystring[querystring.Length - 1] == ',')
                querystring = querystring.Remove(querystring.Length - 1, 1);

            q = q.Match(querystring.ToString());

            int i = 1;

            if (where.Count > 0)
                q = q.Where(where[0]);

            while (i < where.Count)
            {
                q = q.AndWhere(where[i]);
                i++;

            }

            var rq = q.Return(
                (post, nodes) => new PostNode
                {
                    Post = post.As<Node<string>>(),
                    Nodes = nodes.CollectAs<string>()
                })
                .OrderBy("post.creationDate");


        var results = rq.Results.ToList();

        //foreach (var result in results)
        //{

        //    //dynamic p = JsonConvert.DeserializeObject<dynamic>(result.Post.Data);
        //    //dynamic d = JsonConvert.DeserializeObject<dynamic>(result.Nodes.Data);

        //}

        return results;
    }
}

//Some Helper Class just to cast the result.
    public class PostNode 
    {
        public Node<string> Post { get; set; }
        public IEnumerable<Node<string>> Nodes { get; set; }
    }

But as you may noticed it does not have the nodes that is included in the search term via Where Clause in Cypher Query. I am really stopped here for a while, as I can not provide any decent solution for this. so your help may save me a lot. may be i am totally in a wrong direction so please help in any way you can think of.

1

1 Answers

3
votes

It appears that a list of UNKNOWN related nodes are being provisioned, so one of this:

Scenario A

It doesn't matter what EXACTLY those related nodes are, I just want them.

Question: What is intention of retrieving those unknown but related nodes? By answering this chances are this query could be improved for good.

Scenario B

These unknown related nodes are actually known! It's just they are not fully known at time of query execution however down the road somewhere in C# code we will have things like this

if (nodes.Any(_ => _ is HashTag) {...}

Question:

This type of behaviour requires to KNOW the type. Even with reflection or C# dynamic stuff that requirement is still there because Neo4jClient has no way of correlating a bag of JSON data coming from Neo4j into any local type. When Neo4jClient receives bulk of data over wire somehow it should know what type would YOU prefer to represent. This is why queries are always like this:

Return((a, p) => new
{
    Author = a.As<Author>(), //we expect node content to be represented as Author
    Post = p.As<Post>()
})

Neo4jClient does NOT preserve C# types inside your Neo4j database. It would have been nasty to do so. However, idea behind it is that you shouldn't find yourself desperate for it and if you do so then I would recommend looking for problem somewhere else i.e. why would you rely on your client library to describe your domain for you?