Search code examples
asp.netjsonneo4jneo4jclient

How to remove class metadata from Neo4j - Json output


I have the code below on my ASP.Net Web Api project. I return the result to client.

 var query = graphClient.Cypher
                         .Start(new { user = userNode.Reference, cultureInfo = startNode.Reference })
                         .Match("(cultureInfo)-[:CREATES]->(poll:Poll)-[:HAS]->(option:Option)," +
                                                                                "(poll:Poll)<-[:TAGS]-(hashtag:Hashtag)")
                         .Where("NOT (user)-[:ANSWERED]->(poll:Poll)")
                         .AndWhere("NOT (user)-[:SKIPS]->(poll:Poll)")
                         .OptionalMatch("(theme:Theme)-[:PAINTS]->(poll)")
                         .OptionalMatch("(user1:User)-[:ENJOYS]->(poll)")
                         .OptionalMatch("(user)-[e:ENJOYS]->(poll)")
                         .OptionalMatch("(user2)-[a:ANSWERED]->(poll)")
                         .OptionalMatch("(user)-[s:SEARCHES]->(poll)")
                         .Return((poll, option, hashtag, user1, e, a, theme, s) => new
                                                 {
                                                     Poll = poll.As<Poll>(),
                                                     Options = option.CollectAsDistinct<Option>(),
                                                     Hashtag = hashtag.CollectAsDistinct<Hashtag>(),
                                                     Enjoy = user1.CountDistinct(),
                                                     MyEnjoy = e.CountDistinct(),
                                                     Answers = a.CountDistinct(),
                                                     Theme = theme.As<Theme>(),
                                                     MySearch = s.CountDistinct()
                                                 }).OrderByDescending("poll.CreateDate").Limit(Static.Constant.PageSize);

When i test from fiddler, i get such a metadata info from my web api.

[{"poll":{"title":"Güneş gözlüğü","key":"5533637004976467983","createDate":"20131224221100410"},"options":[{"reference":{"id":1287,"nodeType":"MyProject.Domain.Entities.Option, MyProject.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"},"data":{"title":"Kullanmam","imageUrl":null,"viewOrder":2,"key":"5571854810605547089"}},{"reference":{"id":1286,"nodeType":"MyProject.Domain.Entities.Option, MyProject.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"},"data":{"title":"Kullanırım","imageUrl":null,"viewOrder":1,"key":"4676100885647976335"}}],"hashtag":[{"reference":{"id":739,"nodeType":"MyProject.Domain.Entities.Hashtag, MyProject.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"},"data":{"key":"5712268173611849394","name":"HayatTarzı"}}],"enjoy":2,"myEnjoy":1,"answers":2,"theme":{"name":"Sun Flower","backcolor":"#f1c40f","forecolor":"#ffffff","key":"4847432544599442216"},"mySearch":0}]

I mean in "options" and "hashtags" objects, there are some class metadata like

{"reference":{"id":1287,"nodeType":"MyProject.Domain.Entities.Option, MyProject.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}

My question is, how can i remove such class data before sending to the client?


Solution

  • CollectAs and CollectAsDistinct return an IEnumerable<Node<T>> instead of IEnumerable<T>. It's a bit awkward, and less than ideal, but it's how it currently works.

    Node<T> has two properties: Reference and Data. These are what you are seeing.

    You can project this data away:

    var query = graphClient.Cypher
        .Start(new { user = userNode.Reference, cultureInfo = startNode.Reference })
        .Match(
            "(cultureInfo)-[:CREATES]->(poll:Poll)-[:HAS]->(option:Option)",
            "(poll:Poll)<-[:TAGS]-(hashtag:Hashtag)"
        )
        .Where("NOT (user)-[:ANSWERED]->(poll:Poll)")
        .AndWhere("NOT (user)-[:SKIPS]->(poll:Poll)")
        .OptionalMatch("(theme:Theme)-[:PAINTS]->(poll)")
        .OptionalMatch("(user1:User)-[:ENJOYS]->(poll)")
        .OptionalMatch("(user)-[e:ENJOYS]->(poll)")
        .OptionalMatch("(user2)-[a:ANSWERED]->(poll)")
        .OptionalMatch("(user)-[s:SEARCHES]->(poll)")
        .Return((poll, option, hashtag, user1, e, a, theme, s) => new
        {
            Poll = poll.As<Poll>(),
            Options = option.CollectAsDistinct<Option>(),
            Hashtag = hashtag.CollectAsDistinct<Hashtag>(),
            Enjoy = user1.CountDistinct(),
            MyEnjoy = e.CountDistinct(),
            Answers = a.CountDistinct(),
            Theme = theme.As<Theme>(),
            MySearch = s.CountDistinct()
        })
        .OrderByDescending("poll.CreateDate")
        .Limit(Static.Constant.PageSize)
        .Results
        .Select(r => new {
            r.Poll,
            Options = r.Options.Select(n => n.Data),
            Hashtag = r.Hashtag.Select(n => n.Data),
            r.Enjoy,
            r.MyEnjoy,
            r.Answers,
            r.Theme,
            r.MySearch
        });
    

    You have to do the projection after the Results call so that it's not in the Return clause.

    This should be improved when pr/12 lands, so that you don't need to do this.

    Sidenote: You should work towards deprecating that Start clause. Node<T> and NodeReference don't make much sense in a Neo4j 2.0 world, and will slowly be deprecated from Neo4jClient.