Reputation: 17793
I have the following graph structure:
(Building)<-[:PART_OF]-(Floor)
(Floor)<-[:PART_OF]-(Room)
(Room)<-[:INSIDE]-(Asset)
all nodes between a building and an asset are optional, for example, there might be another hierarchy between, or asset can be directly inside a building.
to get all assets in a specific building I use: MATCH (b:Building {id: buildingId})<-[*]-(a:Asset) RETURN a
how can I change this query to return also the PART_OF hierarchies along the paths?
the value of Room, Floor, ... is stored in a 'value' property.
eventually, I want to know for each returned asset, the value of Floor and Room and the labels..
I thought on starting from something like MATCH (b:Building {id: {buildingId}})<-[:PART_OF*0..]-(x)<-[:INSIDE]-(a:Asset) RETURN a, labels(x), x.value
but it returns only the hierarchy which is directly connected to the asset
EDIT:
match (b:Building)<-[:PART_OF*0..]-(x)<-[:PART_OF*0..]-()<-[:INSIDE]-(a:Asset) return a, labels(x), x.value
seems to do the trick, does it look correct?
Upvotes: 1
Views: 3561
Reputation: 1462
You could try examining the paths returned between m:Machine and b:Building. Assuming you don't just want the shortest path(s) and assuming you're using Cypher 2.0 (which it looks like you are), try something like this (note the "p" binding for the path):
MATCH p = (m:Machine)-->(b:Building) RETURN nodes(p), rels(p)
(You can also use "--" instead of "-->" if direction isn't an issue.)
And if you need other info from what's returned, you can always use EXTRACT and other functions, e.g.
RETURN EXTRACT(n IN nodes(p) | p.value)
Hope this helps!
EDIT:
I may have misread the question. You may want to use "allShortestPaths" (around the (m:Machine)-->(b:Building) portion) OR use (m:Machine)-[*]->(b:Building) for variable depth paths (watch the performance, though; you may want to limit the depth) if my original answer doesn't give you what you want.
Upvotes: 2
Reputation: 66967
Assuming you gave your complete graph structure in your question, the following might work for your needs (I assume that the building's 'id' property value is parameterized}:
OPTIONAL MATCH (b:Building {id: {id}})<-[:PART_OF]-(f:Floor)<-[:PART_OF]-(r:Room)<-[:INSIDE]-(a:Asset)
RETURN a, f.value AS fVal, r.value as rVal
UNION
OPTIONAL MATCH (b)<-[:PART_OF]-(f:Floor)<-[:INSIDE]-(a:Asset)
RETURN a, f.value AS fVal, null as rVal
UNION
OPTIONAL MATCH (b)<-[:INSIDE]-(a:Asset)
RETURN a, null AS fVal, null as rVal;
If an asset is not part of a room, then the rVal value will be null. If it is also not part of a floor, then the fVal value will be null.
Also, if there are no assets at all for the building (or any floor/room in the building), then you will still get a single row in the result, but all values will be null.
I did not bother to return any labels, since that should not be necessary with this approach.
Upvotes: 2