Question

I'm experimenting with Neo4j for the first time. I've played a bit with the console (Cypher queries) and now I'm trying to use the .NET client to build a DAL for a .NET application.

For now, my data model is very simple:

  • I have nodes with a label "Folder".
  • These nodes may have a "HAS_SUB_FOLDER" relationship with other folder nodes.

I've successfully done some queries such as

MATCH (n:Folder) 
OPTIONAL MATCH n<-[r:HAS_SUB_FOLDER]-parent 
WITH n, count(parent) AS parents 
WHERE parents = 0 
RETURN n;

to get the parent-less nodes (i.e. "folders in the root directory") which translates to:

var myQuery = client.Cypher.Match("(folder:Folder)")
            .OptionalMatch("folder<-[r:HAS_SUB_FOLDER]-parent")
            .With("folder, count(parent) AS parents")
            .Where("parents=0")
            .Return<Folder>("folder");
        var res = myQuery.Results.ToList();
// res is a List<Folder>, Folder is a Model in my MVC architecture containing attributes like an ID and a Name.

in .NET.

Now I'm trying to, for a given folder node, find the path to its root (to create some navigational breadcrumbs). The query I wrote for that is:

MATCH (current:Folder {id: "...THE_ID..."})
MATCH p = ((current)<-[:HAS_SUB_FOLDER*1..5000]-())
RETURN p;

which seems to work.

I can't, however, achieve that using the .NET client. I want to get a List with the ancestor folders for a given node. I have tried:

var getPathToRoot = client.Cypher.Match("(current:Folder)")
            .Where((Folder current) => current.ID == id)
            .Match("p = ((current) <- [:HAS_SUB_FOLDER*1.." + MAX_DEPTH + "]-())")
            .Return<Folder>("NODES(p)");
var result = myQuery.Results.ToList();

But I get a: Accessed JArray values with invalid key value: "self". Array position index expected. with the following raw JSON:

{
  "columns" : [ "NODES(p)" ],
  "data" : [ [ [ {
    "labels" : "http://localhost:7474/db/data/node/21721/labels",
    "outgoing_relationships" : "http://localhost:7474/db/data/node/21721/relationships/out",
    "data" : {
      "Name" : "YYYYYYYY",
      "ID" : "e5daef28-84c0-42a8-85bf-32516bfe47d0"
    },
    "traverse" : "http://localhost:7474/db/data/node/21721/traverse/{returnType}",
    "all_typed_relationships" : "http://localhost:7474/db/data/node/21721/relationships/all/{-list|&|types}",
    "property" : "http://localhost:7474/db/data/node/21721/properties/{key}",
    "self" : "http://localhost:7474/db/data/node/21721",
    "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/21721/relationships/out/{-list|&|types}",
    "properties" : "http://localhost:7474/db/data/node/21721/properties",
    "incoming_relationships" : "http://localhost:7474/db/data/node/21721/relationships/in",
    "extensions" : {
    },
    "create_relationship" : "http://localhost:7474/db/data/node/21721/relationships",
    "paged_traverse" : "http://localhost:7474/db/data/node/21721/paged/traverse/{returnType}{?pageSize,leaseTime}",
    "all_relationships" : "http://localhost:7474/db/data/node/21721/relationships/all",
    "incoming_typed_relationships" : "http://localhost:7474/db/data/node/21721/relationships/in/{-list|&|types}"}, 
    {
    "labels" : "http://localhost:7474/db/data/node/21720/labels",
    "outgoing_relationships" : "http://localhost:7474/db/data/node/21720/relationships/out",
    "data" : {
       "Name" : "XXXXXXXX",
       "ID" : "31a4cde4-8584-418f-a122-a0f84bbfbf92"
    },
    "traverse" : "http://localhost:7474/db/data/node/21720/traverse/{returnType}",
    "all_typed_relationships" : "http://localhost:7474/db/data/node/21720/relationships/all/{-list|&|types}",
    "property" : "http://localhost:7474/db/data/node/21720/properties/{key}",
    "self" : "http://localhost:7474/db/data/node/21720",
    "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/21720/relationships/out/{-list|&|types}",
    "properties" : "http://localhost:7474/db/data/node/21720/properties",
    "incoming_relationships" : "http://localhost:7474/db/data/node/21720/relationships/in",
    "extensions" : {
    },
    "create_relationship" : "http://localhost:7474/db/data/node/21720/relationships",
    "paged_traverse" : "http://localhost:7474/db/data/node/21720/paged/traverse/{returnType}{?pageSize,leaseTime}",
    "all_relationships" : "http://localhost:7474/db/data/node/21720/relationships/all",
    "incoming_typed_relationships" : "http://localhost:7474/db/data/node/21720/relationships/in/{-list|&|types}"
  } ] ] ]
}

I can see that the data I want is being retrieved but there seems to be a problem when deserializing it. I've tried some variations on my code, with no success and I believe I have a newbie mistake somewhere while trying to get the nodes from the retrieved path.

I'd appreciate if someone could help me with this as I'm just starting using Neo4j (and I'm still "hardwired" to think RDBMS), the documentation is (still) a bit sparse and I'm having issues with debugging (whenever I try to peek into the values of any variable from the Neo4j client library, I get a "Function evaluation disabled because a previous function evaluation timed out. You must continue execution to reenable function evaluation.").

Was it helpful?

Solution

You were close. Just return the nodes in the path as IEnumerable<Folder>.

var getPathToRoot = client.Cypher.Match("(current:Folder)")
    .Where((Folder current) => current.ID == id)
    .Match("p = ((current) <- [:HAS_SUB_FOLDER*1.." + MAX_DEPTH + "]-())")
    .Return(() => Return.As<IEnumerable<Folder>>("nodes(p)"));

This variable length match will actually return multiple paths. If you want longest path, right up to the root of the tree, sort the results by path length (descending) and limit to 1.

You can also omit the minHops and maxHops of the variable length path since they default to 1 and infinity anyway. You can omit maxHops since it defaults to infinity but I would set minHops to 0; otherwise you can't use this query for the root node itself.

This is how I would write it:

var pathToRoot = client.Cypher
    .Match("p = (current:Folder)<-[:HAS_SUB_FOLDER*0..]-()")
    .Where((Folder current) => current.ID == id)
    .Return(() => Return.As<IEnumerable<Folder>>("nodes(p)"))
    .OrderByDescending("length(p)")
    .Limit(1).Results.SingleOrDefault();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top