Neo4j .NET Client - Getting a Path from a Node to its Root

余生长醉 提交于 2019-12-08 06:35:52

问题


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.").


回答1:


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();


来源:https://stackoverflow.com/questions/20659614/neo4j-net-client-getting-a-path-from-a-node-to-its-root

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!