83339

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

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:

<ul><li>I have nodes with a label "Folder".</li> <li>These nodes may have a "HAS_SUB_FOLDER" relationship with other folder nodes.</li> </ul>

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, <strong>for a given folder node, find the path to its root</strong> (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 <em>think RDBMS</em>), 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.").

Answer1:

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.

<s>You can also omit the minHops and maxHops of the variable length path since they default to 1 and infinity anyway.</s> 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();

Recommend

  • Equivalent of .iOS.createNavigationWindow in Android?
  • How to retrieve a part of a string based on an expression (php)
  • Android: How to set status bar and navigation bar semi transparent
  • Appcelerator Titanium Alloy: How to store data on a ScrollableView to use in click event
  • jQuery mobile specific list [closed]
  • How can I remove the file location bar above code in Visual Studio Code?
  • Navigation within section of a page using react router
  • distinguishing html with css sectors
  • WooCommerce Subscriptions - Get product of a specific subscription
  • Help required on onbeforeunload or click on browser back button
  • Jquery ajax and php die()
  • Categories and SubCategories
  • Certain Arabic text gets incorrectly shown while other Arabic text gets showed normally?
  • .NET video play library which allows to change the playback rate?
  • Detecting null parameter in preprocessor macro
  • why xml file does not aligned properly after append the string in beginning and end of the file usin
  • htaccess add www if not subdomain, if subdomain remove www
  • Can you perform a UNION without a subquery in SQLAlchemy?
  • JSON response opens as a file, but I can't access it with JavaScript
  • PostgreSQL Query without WHERE only ORDER BY and LIMIT doesn't use index
  • Accessing IRQ description array within a module and displaying action names
  • Javascript convert timezone issue
  • Display Images one by one with next and previous functionality
  • Do create extension work in single-user mode in postgres?
  • R: gsub and capture
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • Comma separated Values
  • PHP: When would you need the self:: keyword?
  • How to delete a row from a dynamic generate table using jquery?
  • json Serialization in asp
  • SQL merge duplicate rows and join values that are different
  • Rails 2: use form_for to build a form covering multiple objects of the same class
  • Error creating VM instance in Google Compute Engine
  • Acquiring multiple attributes from .xml file in c#
  • Hits per day in Google Big Query
  • how does django model after text[] in postgresql [duplicate]
  • How to stop GridView from loading again when I press back button?
  • reshape alternating columns in less time and using less memory
  • How can I use threading to 'tick' a timer to be accessed by other threads?
  • How to load view controller without button in storyboard?