Cypher query to check locations and sublocations - neo4j

I have Profile node which may be linked to Location node via :LOCATED_IN relationship.
In turn, Location represents unlimited composite structure of nested Location nodes linked with :CONTAINS relationships between them.
I need to find all Profiles which linked to specified location IDs or their parent locations on unlimited levels.
I'm trying to create such Cypher query but it doesn't work as expected. This is what I have so far:
MATCH (d:Profile)-[:LOCATED_IN]-(l:Location)
OPTIONAL MATCH (pl:Location)-[:CONTAINS*]->(l)
WHERE any(x IN l.id WHERE x IN [100,34]) OR any(x IN pl.id WHERE x IN [100,34])
RETURN d;
What am I doing wrong and how to fix it?

I guess this could work
WITH [100,34] AS locationIDs
// get paths, starting at root, ending at the nodes I need
MATCH locationPath=(root:Location)-[:CONTAINS*0..]->(descendant:Location)
WHERE NOT EXISTS (()-[:CONTAINS]->(root))
AND id(descendant) IN (locationIDs+[id(root)])
// create a collection of unique nodes on the locationPaths
UNWIND nodes(locationPath) AS pathNode
WITH COLLECT(DISTINCT pathNode) AS pathNodes
// find profiles linked to at least one of the pathNodes
MATCH (d:Profile)-[:LOCATED_IN]->(pathNode)
WHERE pathNode IN pathNodes
RETURN d

If I understand you correctly, you should start from the Location node and work your way up to the Profile node.
MATCH (l:Location)-[:CONTAINS*0..]->()-[:LOCATED_IN]-(p:Profile)
WHERE l.id IN [100,34]
RETURN distinct p
So you identify your start Location by id.
Then use the CONTAINS*0.., which means that it should traverse the CONTAINS relationship from zero hops (meaning that it can skip it) to theoretically infinite hops and look if any of those nodes have a profile attached to it.
I'm not sure if parent location is a directed CONTAINS relationship from child to parent, but judging from your initial query it is. Other than that, I think it should work.

Related

Neo4J: How to hide a specific node in the graph visualisation?

I have currently visualised a graph between myself and a number of other people.
My Current query is:
MATCH (p)-[:emailed]->(m)
WITH p,count(m) as rels, collect(m) as Contact
WHERE rels > 2
RETURN p,Contact, rels
It creates a pretty complex graph as per image below:
Messy Graph
You can manually remove them by directly clicking on them as per below:
Manually hide node from visualisation
Which then results in a very different looking graph.
Q. How do I change my query to automatically show the graph visualisation without showing the nodes that I wish to remove? (i.e by editing the query, so I dont have to manually remove each one)
By doing either
A) Adding a list of the specific Node ID's in the query to ignore, OR
B) (Ideally) Exclude all nodes that meet a criteria against the node Property
In this case: Ignore [Slug: "myname" ] where includes 'myname'
MATCH (p)-[:emailed]->(m)
WITH p,count(m) as rels, collect(m) as Contact
WHERE rels > 2 AND NOT WHERE p.slug Contains 'Mahdi'
RETURN p,Contact, rels
Thanks for any help!
I would change it slightly. If you collect the actual :emailed relationships rather than just counting the node they are connect to you can use them in your result set. Then if you turn off autocomplete as JeromeB suggests above then you will actually see some relationship. If you turn off autocomplete in your current query there will only be nodes and no relationships which I don't think you are after (unless of course you are).
You could also check to make sure that the p.slug attribute exists when testing for CONTAINS otherwise if the attribute does not exist you will not generate any results for that row.
MATCH (p:User)-[r:emailed]->(m:User)
WITH p, COLLECT(r) as rels, COLLECT(m) as contact
WHERE (NOT p.slug CONTAINS 'Mahdi' OR NOT EXISTS(p.slug))
AND size(rels) > 2
RETURN p, contact, rels
I would also add a label to the nodes in the match and an index on the slug property.
The autocomplete is 'Connect result nodes' in the Gear tab.

Cypher - Delete node with given property and reconnect graph

I have a graph consisting of paths.
I need to delete all nodes, that have a property:
linksTo:'javascript'
After deleting i have to reconnect the paths. This means i need to create a new relationship for each gap. This relationship has a property named deltaTime that holds some integer value. This value (deltaTime) should be the sum of all deltaTime-properties of the deleted relationships of this path. Please look at the following picture for better understanding.
I don't know how to detect multiple "bad" nodes in a row, with a variable row-length.
It would help if you could provide the labels involved in your graph, as well as the relationship types you're using.
Assuming all these paths are chains (only single relationships connecting each node), something like this should work for you:
// first, add a label on all the nodes we plan on deleting
// it helps if they already have the same label especially if linksTo property is indexed.
MATCH (n{linksTo:'javascript'})
SET n:ToDelete
With the appropriate nodes labeled, we'll find the segments of nodes to delete, the surrounding nodes that need to be connected, and create the new relationship. We ensure a and b are start and end nodes of the chain by ensuring there are no :ToDelete nodes linking to a, or from b.
MATCH (a:ToDelete)
WHERE NOT (:ToDelete)-->(a)
AND ()-->(a)
MATCH p = (a)-[rel*0..]->(b:ToDelete)
WHERE ALL(node in nodes(p) WHERE node:ToDelete)
AND NOT (b)-->(:ToDelete)
AND (b)-->()
WITH a, b, REDUCE(s = 0, r IN rel | s + r.value) as sum
// now get the adjacent nodes we need to connect
MATCH (x)-[r1]->(a), (b)-[r2]->(y)
WITH x, y, sum + r1.value + r2.value AS sumValue
// making up relationship type and property name as I don't know what you're using
MERGE (x)-[:Rel{value: sumValue}]->(y)
Finally, when you're sure the new relationships look correct, delete the nodes you no longer need.
MATCH (n:ToDelete)
DETACH DELETE n

How do I return nodes in neo4j that have a certain relationship, and then return nodes that have a different relationship with the first nodes?

I have a bunch of nodes that "refer" to other nodes. The nodes referred to (refer_to being the relationship) may then have a relationship to another node called changed_to. Those nodes that are related by the changed_to relationship may also have another changed_to relationship with yet another node. I want to return the nodes referred to, but also the nodes that the referred nodes were changed into. I tried a query that returns referred to nodes combined with a union with an optional match of ReferencedNode changed to ResultNode, but I don't think this will work as it will only get me the referenced node plus the first changed to node and nothing after that, assuming that would work at all to begin with. How can I make a query with the described behavior?
Edit:
This is an example of the relationships going on. I would like to return the referenced to node and the node that the referenced node was ultimately became, with some indicator showing that it became that node ultimately.
Can you give some examples of queries you've tried? Here's what I'm thinking:
MATCH path=(n)-[:refer_to]->(o)-[:changed_to*1..5]->(p)
WHERE n.id = {start_id}
RETURN nodes(path), rels(path)
Of course I don't know if you have an id property so that might need to change. Also you'll be passing in a start_id parameter here.
If you want to return the "references" node and the last "changed_to" node if there is one, you can first match the relationship you know is there, then optionally match at variable depth the path that may be there. If there is more than one "changed_to" relationship you will have more than one result item at this point. If you want all the "changed_to" nodes you can return now, but if you want only the last one you can order the result items by path depth descending with a limit of 1 to get the longest path and then return the last node in that path. That query could look something like
MATCH (n)-[:REFERENCES]->(o)
WHERE n.uid = {uid}
OPTIONAL MATCH path=o-[:CHANGED_TO*1..5]->(p)
WITH n, o, path
ORDER BY length(path) DESC
LIMIT 1
RETURN n, o, nodes(path)[-1]
This returns the start node, the "references" node and
nothing when there is no "changed_to" node
the one "changed_to" node when there is only one
the last "changed_to" node when there is more than one
You can test the query in this console. It contains these three cases and you can test them by replacing {uid} above with the values 1,5 and 8 to get the starting nodes for the three paths.

Neo4j cypher - Counting immediate children of root nodes

I'm struggling with a problem despite having read a lot of documentation... I'm trying to find my graph root node (or nodes, they may be several top nodes) and counting their immediate children (all relations are typed :BELONGS_TO)
My graph looks like this (cf. attached screenshot). I have been trying the following query which works as long as the root node only has ONE incomming relationship, and it doesn not when it has more than one. (i'm not realy familiar with the cyhper language yet).
MATCH (n:Somelabel) WHERE NOT (()-[:BELONGS_TO]->(n:Somelabel)) RETURN n
Any help would be much appreciated ! (i haven't even tried to count the root nodes immediate children yet...which would be "2" according to my graph)
Correct query was given by cybersam
MATCH (n:Somelabel) WHERE NOT (n)-[:BELONGS_TO]->() RETURN n;
MATCH (n:Somelabel)<-[:BELONGS_TO]-(c:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->() RETURN n, count(c);
Based on your diagram, it looks like you are actually looking for "leaf" nodes. This query will search for all Somelabel nodes that have no outgoing relationships, and return each such node along with a count of the number of distinct nodes that have a relationship pointing to that node.
MATCH (n:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->()
OPTIONAL MATCH (m)-[:BELONGS_TO]->(n)
RETURN n, COUNT(DISTINCT m);
If you are actually looking for all "root" nodes, your original query would have worked.
As a sanity check, if you have a specific node that you believe is a "leaf" node (let's say it has an id value of 123), this query should return a single row with null values for r and m. If you get non-null results, then you actually have outgoing relationships.
MATCH (n {id:123})
OPTIONAL MATCH (n)-[r]->(m)
RETURN r, m

How do I get all relationships between nodes on a path

I am trying to follow a certain relationship type and return all the nodes and (other) relationships on that path but not to follow paths through nodes that are not part of the path.
Below is the live query that I have set up to demonstrate.
http://console.neo4j.org/?id=b6sxoh
In the example I do not want the relationship through B->E->C to be included in the results because there is no 'depends_on' relationship between them.
Below is one of my many attempts... (also in the console).
START me=node:node_auto_index(name='A')
MATCH p=me-[d:depends_on*]->others
WITH me,others
MATCH p=me-[r*]-others
RETURN DISTINCT relationships(p);
I would love some help please!
One way to do this is to iterate through each pair of nodes on the matched path for the pattern "p=me-[d:depends_on*]->others", and find any other relationships between them.
START me=node:node_auto_index(name='A')
MATCH me-[:depends_on*0..]->(previous)-[:depends_on]->last
With previous, last
Match previous-[r]-last
Where type(r) <> 'depends_on'
Return r
Since each matched path for the pattern "me-[d:depends_on*]->others" is augmented with a new relationship as the last relationship, to iterate through all the relationships on the matched path is to iterate through each last relationship on the matched paths. So for each matched path, we capture the start node and the end node of the last relationship as "previous" and "last" and then find the relationships "r" between them, filter "r" with the "Where" clause based on the type of the relationship r, return only those relationships r that are not of the type "depends_on".

Resources