cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Extract list of Nodes and Labels from path

Hi,

I'm working on a project that stores our customers relationships in Neo4j. Our model looks like this: (Client) - [PARENT_OF] - (Client). Each Client can have up to 3 different labels assigned.

I made a query that at first glance should work but it's not returning the nodes from the path as a List.

Here is my query "MATCH p = (n:Client)-[r:PARENT_OF*]->(t:Client) WHERE n.code="MYCODE" RETURN nodes(p) as nodes , labels(n) as labels"

In the docs I read that the nodes() function takes a path as parameter and then outputs the nodes from the path as a list. When I execute the query from the browser it returns each node from nodes as an array containing the parent node and its child.

Nodes | Labels
[ ["Label1", "Label2"]
{node1},{node2}
],
[ ["Label1", "Label2"]
{node1},{node3}
],
[ ["Label1", "Label2"]
{node2},{node4}
]

In my backend (Java + Spring) while debugging I get the labels correctly but it isnt mapping the Nodes as they aren't a single Entity but an array as I said.

Below I attached an image from the browser output when I run the query. How can I make it so there's only one node instead of 2?

Thanks

1 ACCEPTED SOLUTION

Hi @marcos.stival,
Welcome to the community!

What you're looking for is a way to flatten your list of lists, and then unwind (or pivot them).

MATCH p = (n:Client)-[r:PARENT_OF*]->(t:Client) 
WHERE n.Code="MYCODE"
// nodes(p) is an array of arrays. the reduce is similar to a flat function.
WITH reduce(output = [], n IN nodes(p) | output + n ) as nodeCollection
// here we take the single row of the flattened array and pivot it to rows.
UNWIND nodeCollection as client
// once we have each client in it's own row, then we call labels 
// Also don't forget the distinct! 
// Remember the arrays simply flatten out each path, 2 of your nodes show up in multiple paths.
RETURN distinct client, labels(client)

I hope that was informative while also helping answer the question.
If you have any other follow on questions, let me know

-Mike

View solution in original post

5 REPLIES 5

shan
Graph Buddy

Hi,

It's not still clear what you are trying to do and what is the expected output. You get 3 rows in the output because there are 3 paths. nodes returns all nodes in a path incuding the first and the last nodes. If you don't need the first one, you can use the tail function. For example, tail([1,2,3]) returns [2,3]. So just pass the nodes(p) to the tail function and you will get all nodes but the first one.
Sorry if I am not answering your question. I did my best given the level of details I found in the question.

Hi Shan, thanks for you reply.

The expected output is a list of the nodes from the path.

I have a path that looks like this :

I want the output from my cypher query to return a list of those nodes with each node's label (most nodes usually have 2 labels)

For the path from the image it should return a list with 7 nodes. Instead when I run the query I get the OP image result which is an array containing the parent node and a child.

This is the response I need:

[
{
"node": {nodedata},
"labels" : ["label1","label2"]
},
{
"node": {nodedata},
"labels" : ["label1","label2"]
},
{
"node": {nodedata},
"labels" : ["label1","label2"]
}
]

This is the response I got:

[
{
"nodes": [{node1},{node2}]
"labels": ["label1","label2"]
},
{
"nodes": [{node1},{node2}]
"labels": ["label1","label2"]
},
{
"nodes": [{node1},{node2}]
"labels": ["label1","label2"]
},
{
"nodes": [{node1},{node2}]
"labels": ["label1","label2"]
}
]

Hi @marcos.stival,
Welcome to the community!

What you're looking for is a way to flatten your list of lists, and then unwind (or pivot them).

MATCH p = (n:Client)-[r:PARENT_OF*]->(t:Client) 
WHERE n.Code="MYCODE"
// nodes(p) is an array of arrays. the reduce is similar to a flat function.
WITH reduce(output = [], n IN nodes(p) | output + n ) as nodeCollection
// here we take the single row of the flattened array and pivot it to rows.
UNWIND nodeCollection as client
// once we have each client in it's own row, then we call labels 
// Also don't forget the distinct! 
// Remember the arrays simply flatten out each path, 2 of your nodes show up in multiple paths.
RETURN distinct client, labels(client)

I hope that was informative while also helping answer the question.
If you have any other follow on questions, let me know

-Mike

Oh my god Mike, thanks for your reply it works like a charm!
I have yet to understand how flat functions works and the syntax for the reduce function too but for the sake of the query I think I get it.

Thanks again.
Have a very nice day!

Happy to help.

for using the reduce to flatten,

the code reduce(output = [ ], n in nodes(p) | output +n) is translated to

  1. output = [ ] => the output starts off as an empty array .
  2. n in nodes(p) => for each element n in the collection nodes(p)
    a. recall at this point n is itself an array.
  3. ouput + n => for each n do this to transform from n to output.
  4. the reduce basically says loop over our collection (#2), doing some action(#3)

@mark.needham also wrote a good explanation of how to use reduce to flatten data here
Neo4j: Cypher - Flatten a collection

-Mike