neo4jcypherneo4jclient

Problem with WHERE in Neo4J, deserialization error


I'm using Neo4JClient in .NET Core web application (I created it in VisualStudio version 2019 template) and I had code that works as expected for my example.

I have 3 types of node: Category(important property name - string), Document(important CreatedBy - represents name of User who created it, other properties are used after WHERE), User(important Username - string). Document can have TAG relationship with Category and User can have INTERESTED_IN relationship with Category.

First I created one query to return Document if it have TAG to Category and if User is INTERESTED_IN this Category (Note: I don't have multiple relationships between nodes). Also number of connections with Category is counted so if I have too many Documents method returns only 10 with most connections.

    public async Task<IActionResult> GetNewsFeed(string username)
{
    string match = $"(a:User{{Username: '{username}'}})-[:INTERESTED_IN]->(res:Category)<-[:TAG]-(b:Document)";
    string where = $"NOT(b.isArchived AND c.isArchived AND b.CreatedBy =~ '{username}')";
    string with = "b.name AS name, b.CreatedBy AS creator, b.Pictures AS pictures, b.Paragraphs AS paragraphs, COUNT(res) AS interest1";
    
    var result = _context.Cypher.Match(match)
                             //.Where(where)
                               .With(with)
                               .Return((name, creator, pictures, paragraphs, interest1)=> new SimpleNewsFeedDTO { 
                                                                                                        Name = name.As<string>()
                                                                                                      , Creator = creator.As<string>()
                                                                                                      , Pictures = pictures.As<string[]>()
                                                                                                      , Paragraphs = paragraphs.As<string[]>()
                                                                                                      , Interest = interest1.As<int>() })  
                               .OrderBy("interest1 DESC")
                               .Limit(10)
                               .ResultsAsync);
    return new JsonResult(await result);
}

When I provide correct Username I can see results in right order, but I also want to filter Documents CreatedBy that User (I want to exclude documents created by user), but when I uncomment Where and send request I get following error:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.ArgumentException: Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied.

First, try and review the exception below to work out what broke.

If it's not obvious, you can ask for help at http://stackoverflow.com/questions/tagged/neo4jclient

Include the full text of this exception, including this message, the stack trace, and all of the inner exception details.

Include the full type definition of ExtraBlog.DTOs.SimpleNewsFeedDTO.

Include this raw JSON, with any sensitive values replaced with non-sensitive equivalents:

 (Parameter 'content')
 ---> System.ArgumentNullException: Value cannot be null. (Parameter 'input')
   at System.Text.RegularExpressions.Regex.Replace(String input, String replacement)
   at Neo4jClient.Serialization.CommonDeserializerMethods.ReplaceAllDateInstancesWithNeoDates(String content)
   at Neo4jClient.Serialization.CypherJsonDeserializer`1.Deserialize(String content, Boolean isHttp)
   --- End of inner exception stack trace ---
   at Neo4jClient.Serialization.CypherJsonDeserializer`1.Deserialize(String content, Boolean isHttp)
   at Neo4jClient.GraphClient.Neo4jClient.IRawGraphClient.ExecuteGetCypherResultsAsync[TResult](CypherQuery query)
   at ExtraBlog.Controllers.UserController.GetNewsFeed(String username) in E:\GithubRepo\NapredneBaze\Neo4JProject\extra-blog\ExtraBlog\Controllers\UsersController.cs:line 39
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Also when I run something like this in Neo4J browser I get the same result with or without WHERE:

MATCH (a:User{Username: 'NN'})-[:INTERESTED_IN]->(res:Category)<-[t:TAG]-(b:Document)
WHERE (NOT(b.isArchived AND res.isArchived AND b.CreatedBy =~ 'NN'))
WITH b, COUNT(res) AS interest1
RETURN b.name, interest1
ORDER BY interest1 DESC
LIMIT 10

So my question is: why I can't run my method in Visual Studio, and why this query doesn't return what I was expecting?


Solution

  • With these things, it's always good to check what you are generating from the client. To that end you should look at the query.DebugQueryText property. If you do, you'll see the query you would generate would look like this:

    MATCH (a:User{Username: 'NN'})-[:INTERESTED_IN]->(res:Category)<-[:TAG]-(b:Document)
    WHERE NOT(b.isArchived AND c.isArchived AND b.CreatedBy =~ 'NN')
    WITH b.name AS name, b.CreatedBy AS creator, b.Pictures AS pictures, b.Paragraphs AS paragraphs, COUNT(res) AS interest1
    RETURN name AS Name, creator AS Creator, pictures AS Pictures, paragraphs AS Paragraphs, interest1 AS Interest
    ORDER BY interest1 DESC
    LIMIT 10
    

    If you try to execute that in your browser - it won't work, and that's because you use an alias c to access the isArchived property, but there is no c in your MATCH.