My database stores family relationships.
What I am trying to do is to return the whole family tree of a person with a certain ID.
I have tried the following query:
MATCH (p:Person {id:'1887'})-[r*1..3]-(k:Person)
RETURN distinct(p), r, k
but I didn't get the result that I wanted.
To make it more clear, I would like to get all the relationships that a person with specified ID has, along with the relationships of all the other nodes that he is connected to.
To explain further, here is an example:
Boris is a parent of Mike and Anna. Apart of seeing Boris' relationship to them, I also want to see Mike and Anna's further relationships with their subgraphs.
I believe you should try returning the complete path, like this:
MATCH path = (p:Person {id:'1887'})-[r*1..3]-(k:Person)
RETURN path
This query will store each the path between a person with id = 1887 and another person with depth 1 to 3 and return it. Or if you are interested only in the nodes you can extract it with the nodes() function:
MATCH path = (p:Person {id:'1887'})-[r*1..3]-(k:Person)
RETURN nodes(path)
Related
I am experimenting with creating multiple relationships between nodes to represent the importance between two given nodes.
For example, I want to know what 'genre' of reading material is most important to Joe.
I want a way to match the Joe node to genre nodes only if there is some number or greater relationships between them.
So, if I want matches with 3 or more relationships, I should get a graph with Joe --> Fantasy
I know I can get this when both endpoints are defined:
MATCH (p:PERSON {name:'Joe'})-[r]->(g: GENRE {name:'Fantasy'})
RETURN count(r)
What I want is something like:
MATCH p = (p:PERSON {name:'Joe'})-[r]->()
WHERE *pair_relationship_count*(r) >= 3
RETURN p
This is my proposition:
MATCH path = (p:PERSON {name:'Joe'})-[r]->()
WITH collect(path) as paths, collect(r) as pair_count
WITH paths WHERE size(pair_count) >= 3
UNWIND paths as path
RETURN path
But maybe it is more efficient to have one relationship with an internal count property on one relationship for each couple of nodes.
First, I think you can achieve your goal using WITH clause:
MATCH path = (:PERSON {name:'Joe'})-[r]->(:GENRE {name:'Fantasy'})
WITH path, count(r) as count
WHERE count > 3
RETURN path
But using one relationship for each read "event" seems to be a bad approach. Maybe you should use an integer property in the relationship, then increment this property for each "read". This way you can do queries like:
MATCH path = (:PERSON {name:'Joe'})-[r]->(:GENRE {name:'Fantasy'})
WHERE r.count > 3
RETURN path
To get a collection of all READS paths for "Joe" that involve each genre that he has read at least 3 times:
MATCH p = (:PERSON {name:'Joe'})-[:READS]->(genre)
WITH genre, COLLECT(p) AS paths
WHERE SIZE(paths) >= 3
RETURN genre, paths;
suppose I have a tree where certain nodes have a relationship of a give type, how would I return all nodes in the tree except for those with the given relationship and its descendants.
I've gotten half way there with something like this (the tree is built on has links):
match (root: {Name: 'Root'})-[:has*]->(n) where not (n)-[:Exemption]-() return n
but, of course, this excludes nodes that have a relationship of type Exemption but not its descendants, so the descendants show up as unconnected nodes
how do I structure the query?
This query should work:
MATCH p=({Name: 'Root'})-[:has*]->(n)
WHERE NONE(x IN NODES(p) WHERE (x)-[:Exemption]-())
RETURN n;
It filters out any :has relationship paths with a node that (also) has an :Exemption relationship.
I would probably split the path up into two parts:
MATCH p=(:Label {Name: 'Root'})-[:has*]->(n) WHERE NOT EXISTS ((n)-[:Exemption]->())
MATCH p2 = (n)-[:has*]->(m) WHERE NOT (m)-[:has]->()
RETURN p,p2;
after some experimentation, this worked:
match (root: {Name: 'Root'})-[:has*]->(n)
match (m)-[:has*]->(n)
where not (m)-[:Exemption]-()
return n
which essentially says: find a path, for any node on that path, traverse back up to make sure that none of the ancestors show an exception. so what I'm negating here is the subpath created with the second match
I am trying to find the hierarchy - both upward and downward for the following domain model. As being new to neo4j I am having some hurdle to get the right hierarchy with the cypher query.
Any assistance or sample would be a great help to me...
(:Person{id=1})-[HAS_CHILD]->(:Person{id=2})-[HAS_CHILD]->(:Person{id=3})-[HAS_CHILD]->(:Person{id=4})-[HAS_CHILD]->(:Person{id=5})
....like that to a very deep level & one person can have multiple children.
I am trying to build some query to find
A Person and all his children hierarchy
A person and his parent hierarchy
Relation ship between two person - if any
A Person and all his children hierarchy - up to a specific depth
These should work.
The WHERE clauses are for eliminating subpaths. The answer for #4 cannot use the same WHERE clause, so the results will contain subpaths.
1.
MATCH p=(:Person{id:1})-[:HAS_CHILD*]->(c)
WHERE NOT (c)-[:HAS_CHILD]->()
RETURN NODES(p);
2.
MATCH p=(:Person { id:5 })<-[:HAS_CHILD*]-(ancestor)
WHERE NOT (ancestor)<-[:HAS_CHILD]-()
RETURN NODES(p);
3.
MATCH p=(p5:Person { id:5 })-[:HAS_CHILD*]-(p1:Person { id:1 })
RETURN NODES(p);
4. Using a depth up to 5:
MATCH p=(:Person{id:1})-[:HAS_CHILD*1..5]->(c)
RETURN NODES(p);
Using your datamodel consisting of (:Person)-[:HAS_CHILD]->(:Person) these queries should return the data you are looking for (let's also assume you have a unique name property on each Person node to facilitate a lookup by name, but you could also use any unique id/property):
A person and all his children
We can use a variable length path pattern here to match on patterns containing multiple HAS_CHILD relationships.
MATCH (p:Person)-[:HAS_CHILD*]->(child:Person)
WHERE p.name = "Bob Loblaw"
RETURN child;
A person and his parent hierarchy
Very similar to the above query, but we just reverse the relationship direction.
MATCH (p:Person)<-[:HAS_CHILD*]-(ancestor:Person)
WHERE p.name = "Bob Loblaw"
RETURN ancestor;
Relationship between two person - if any
We can use the shortestPath function to find the shortest path between two nodes in the graph. This query will return no rows if no path is found.
MATCH path=shortestPath((p:Person {name: "Bob Loblaw"})-[*]-(o:Person {name: "Louise Bluth"}))
RETURN path
A person and their child hierarchy - up to a specific depth
This query is very similar to the previous "person and all his children query" however we can specify bounds on the variable length path. Note: an upper bound should always be specified with variable length paths to avoid very long running queries.
MATCH (p:Person)-[:HAS_CHILD*1..5]->(child:Person)
WHERE p.name = "Bob Loblaw"
RETURN child;
Before I explain the problem I am facing, I think it would be better if I explain the structure of my graph database a bit. Following are the Nodes, Relationships and Properties in my neo4j graph database:
Nodes:
User
Email
Phone
Book
BlogPost
Relationships:
HAS (used as : user -[:HAS]-> (e:Email|Phone))
READ (used as : user - [:READ] -> (b:Book|BlogPost))
WROTE (used as: user - [:WROTE] -> (b:Book|BlogPost))
Properties:
uid (associated with nodes User, Book, BlogPost, Email, Phone)
name (associated with node User)
title (associated with nodes Book, BlogPost)
email (associated with node Email)
phone (associeated with node Phone)
Before I actually put up my question I would like to state that I am pretty new to the neo4j technology so I do understand that solution to my problem might be basic.
What I am trying to achieve ?
I want to get all the shortest paths between two users and then for each node between those two users in a path I would like to get:
The email address and/or phone number if the node is a User node.
Title of the node if it's a Book or a BlogPost node.
Where am I stuck ?
I can get the paths using the following cypher query:
match (u1: User {uid: '0001'}),
(u2: User{uid: '0002'}),
paths = allShortestPaths((u1)-[*..4]-(u2))
return paths
After getting the paths I can get the properties of the nodes, relationships in the path using the extract, nodes, relationships functions if I ammend the above query as follows:
match (u1: User {uid: '0001'}),
(u2: User{uid: '0002'}),
paths= allShortestPaths((u1)-[*..4]-(u2))
with extract(n in nodes(paths) | [n.name]) as nds,
extract(r in relationships(paths)| [type(r)]) as rels
return nds,rels
The problem
But what I really want to get is the email and phone properties off Email and Phone nodes that are connected to any nodes within a given path.
I have gone through the official documentation and a lot of blog posts but could not find any solution or a similar problem for that matter.
How can I achieve the above mentioned ?
PS: I would like to achieve this in a single query
Thanks
Does something like this meet your needs?
Major edits below:
In the return statement below:
Get the list of nodes in the path excluding the first and last nodes
Use labels to inspect only user, book and blog posts
Filter out the intermediate user nodes into one collection
Filter out the intermediate book/blog posts and extract the titles into another collection
Iterate over the intermediate user nodes to find the associated email and or phone nodes (credit #FrobberOfBits)
Here is the cypher:
// match the user nodes and the shortest intermediate paths between them
match (u1:User {uid: '0001'})
, (u2:User {uid: '0002'})
, path = allShortestPaths((u1)-[*..4]-(u2))
// filter out the intermediate user nodes into one collection
with filter(n IN nodes(path)[1..length(nodes(path))-1]
where any(x in labels(n) where x = 'User'))
as intermediate_users
// filter out the intermediate book titles into another collection
, [n IN nodes(path)[1..length(nodes(path))-1]
where any(x in labels(n) where x in ['Book','BlogPost'])
| n.title ]
as intermediate_books_posts
// iterate through the intermediate user nodes
// and optionally match email and phone nodes
unwind intermediate_users as u
optional match (e:Email)<--u-->(p:Phone)
return u.name, e.address, p.number, intermediate_books_posts
I am trying to query a graph to return all of the paths with a set of specified relationships.
The graph I have contains the following nodes: Person
The relationships which connect two people are: knows, married
So an example of some data are:
c:Person-[:knows]->b:Person
a:Person-[:married]->c:Person
d:Person-[knows]-> a:Person
In my query I would like to be able to find all paths that contain both relationships 'knows' and 'married'; however, I don't care about the ordering of such relationships in the paths. For example, my query should return the following paths:
1) a:Person-[:married]->c:Person-[:knows]->b:Person
2) d:Person-[:knows]->a:Person-[:married]->c:Person
I tried the following query
MATCH p=(a)-[:KNOWS|MARRIED*1..3]-(b)
RETURN p
However, it returned the paths only having knows relationship or the paths only having married relationship, but not both.
Is there any way of finding the paths I want? Many thanks!
You can try this
MATCH p=(a)-[rel*]-(b)
WHERE type(rel)='KNOWS' OR type(rel)='MARRIED'
RETURN p
It will provide you all paths
MATCH p = (a:Person)-[rels:KNOWS|MARRIED*]->(b:Person)
WITH p, EXTRACT(r IN rels | TYPE(r)) AS types
WHERE 'KNOWS' IN types AND 'MARRIED' IN types
RETURN p