I was making some requests on Neo4j, and I've a little trouble at making one in particular.
These are the nodes and relationships I have on my database
Two of the elements:
I want to return the persons who are driving ("conduire") the same "Voiture" as Alice.
This is what I wrote:
MATCH ((a:Personne)-[p:Conduire]->(b:Vehicule))
WHERE b.`Type`='Voiture' AND id(b) in [MATCH ((a:Personne)-[p:Conduire]->(b:Vehicule))
WHERE a.Nom='Alice'
RETURN id(b)]
RETURN a.Nom
Here is the query to return the persons who are driving the same car as Alice. Note that this will not return Alice because the match on b will not repeat the match made on a.
MATCH (a:Personne)-[:Conduire]->(:Vehicule)<-[:Conduire]-(b:Personne)
WHERE a.Nom='Alice'
RETURN b.Nom
I have a trouble when fetch the unrelated nodes. pls refer the image attached. as per the image "Mother of john" is the current user. i want to find which nodes all are unrelated for "Mother of john"
(Eg: "Father of Mohanraj" , etc.)
here is my query
match (m:member) where id(m) = 36
with m
match (p:member)-[*]-()
with collect(p) as parents
match (w:wedding)<-[:WED_TO]-(i)
where not i in parents
return i
Thanks in advance
In your query, m is not used to filter the results of the second part.
I would go along the lines below:
// return the user
MATCH (m:member) where id(m) = 36
WITH m
// return all members that are not related to m
MATCH (p:member)
WHERE NOT (p)-[:WED_TO|PARENT_FROM*]-(m)
RETURN p
This is a slightly different question from one answered here:
Update multiple nodes in a single query, each with different property / value pairs
The selected answer to that question presented a nifty query to update many nodes by their 'uuid':
UNWIND { data } AS d
MERGE (x {uuid: d.uuid})
SET x += d.props
My question is how would you accomplish this if you wanted to select by ID(x)? While most of my nodes do have a uuid property, my relationships do not and I need to update their properties as well.
Thanks!
You'll need to process your nodes and relationships separately. Relationships would process similar to this:
UNWIND { data } AS d
MATCH ()-[r]-()
WHERE id(r) = d.id
SET r += d.props
Node processing would be similar, just use MATCH (n) WHERE id(n) = d.id
I've been playing with neo4j for a geneology site and it's worked great!
I've run into a snag where finding the starting node isn't as easy. Looking through the docs and the posts online I haven't seen anything that hints at this so maybe it isn't possible.
What I would like to do is pass in a list of genders and from that list follow a specific path through the nodes to get a single node.
in context of the family:
I want to get my mother's father's mother's mother. so I have my id so I would start there and traverse four nodes from mine.
so pseudo query would be
select person (follow childof relationship)
where starting node is me
where firstNode.gender == female
AND secondNode.gender == male
AND thirdNode.gender == female
AND fourthNode.gender == female
Focusing on the general solution:
MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND extract(x in tail(nodes(p)) | x.gender) = {genders}
RETURN ancestor
here's how it works:
match the starting node by id
match all the variable-length paths going to any ancestor
constrain the length of the path (i.e. the number of relationships, which is the same as the number of ancestors), as you can't parameterize the length in the query
extract the genders in the path
nodes(p) returns all the nodes in the path, including the starting node
tail(nodes(p)) skips the first element of the list, i.e. the starting node, so now we only have the ancestors
extract() extracts the genders of all the ancestor nodes, i.e. it transforms the list of ancestor nodes into their genders
the extracted list of genders can be compared to the parameter
if the path matched, we can return the bound ancestor, which is the end of the path
However, I don't think it will be faster than the explicit solution, though the performance could remain comparable. On my small test data (just 5 nodes), the general solution does 26 DB accesses whereas the specific solution only does 22, as reported by PROFILE. Further profiling would be needed on a larger database to compare the performances:
PROFILE MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND extract(x in tail(nodes(p)) | x.gender) = {genders}
RETURN ancestor
The general solution has the advantage of being a single query which won't need to be parsed again by the Cypher engine, whereas each generated query will need to be parsed.
It was more simple than I thought. Maybe there is still a better way so I'll leave this open for a bit.
the query would be
MATCH (n1:Person { Id: 'f59c40de-506d-4829-a765-7a3ae94af8d1' })
<-[:CHILDOF]-(n2 { Gender:'0'})
<-[:CHILDOF]-(n3 { Gender:'1'})
<-[:CHILDOF]-(n4 { Gender:'1'})
RETURN n4
and for each generation back would add a new row.
The equivalent query would look something like this:
MATCH (me:Person)
WHERE me.ID = ?
WITH me
MATCH (me)-[r:childof*4]->(ancestor:Person)
WITH ancestor, EXTRACT(rel IN r | endNode(rel).gender) AS genders
WHERE genders = ?
RETURN ancestor
Disclaimer, I haven't double-checked the syntax.
In Neo4j you typically find your start node first, typically by an ID of some sort (modify as required to match on a unique property). We then traverse a number of relationships to an ancestor, extract the gender property of all end nodes in the traversed relationships, and compare the genders to the expected list of genders (you'll need to make sure the argument is a bracketed list in the desired order).
Note that this approach filters down all possible results with that degree of childof relationship as opposed to walking your graph, so higher degrees of relationship (the higher the degree of ancestry you're querying), the slower the call will get.
I'm also unsure if you can parameterize the degree of the variable relationship, so that might prevent this from being a generalized solution for any degree of ancestry.
I'm not sure if you want a generic query which can work whatever the collection of genders you pass, or a specific solution.
Here's the specific solution: you match the path with the wanted length, and match each gender, as you've already noted in your own answer.
MATCH (me:Person)-[:IS_CHILD_OF]->(p1:Person)
-[:IS_CHILD_OF]->(p2:Person)
-[:IS_CHILD_OF]->(p3:Person)
-[:IS_CHILD_OF]->(p4:Person)
WHERE me.uuid = {uuid}
AND p1.gender = {genders}[0]
AND p2.gender = {genders}[1]
AND p3.gender = {genders}[2]
AND p4.gender = {genders}[3]
RETURN p4
Now, if you want to pass in a list of genders of an arbitrary length, it's actually possible. You match a variable-length path, make sure it has the right length (matching the number of genders), then match each gender in sequence.
MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND all(i IN range(0, size({genders}) - 1)
WHERE {genders}[i] = extract(x in tail(nodes(p)) | x.gender)[i])
RETURN ancestor
Building on #InverseFalcon's answer, you can actually compare collections, which simplifies the query:
MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND extract(x in tail(nodes(p)) | x.gender) = {genders}
RETURN ancestor
how do i add relationships to nodes returned by a cypher query?
I have written a query that returns me all the person nodes who have the same surname who live at the same address. I now want to add a relationship between these person nodes to indicate they are the same person. The query below returns me 3 person nodes and I want to add a relationship from the first node (returned by the ORDER BY) to the other 2.
MATCH (a:Address) <-[LIVES_AT]-(p:Person)
WITH a as addnode, p.surname as psurname, COUNT(p.name_urn) as c
WHERE c > 1
MATCH (a2:Address{address_urn:addnode.address_urn})<-[LIVES_AT]- (p2:Person{surname:psurname})
WITH p2 as p2node
ORDER BY CASE
WHEN p2node.master_record = 'Y'
THEN
1
ELSE
2
END
WITH collect(p2node) as colp2node
RETURN colp2node
Hope this makes sense? Please advise if there is a better way of doing this.
Something like this should work for you:
MATCH (a:Address)<-[LIVES_AT]-(p:Person)
WITH a, p.surname AS psurname, COUNT(p.name_urn) AS c
WHERE c > 1
MATCH (a2:Address { address_urn:a.address_urn })<-[LIVES_AT]-(p2:Person { surname:psurname })
WITH p2
ORDER BY CASE WHEN p2.master_record = 'Y' THEN 1 ELSE 2 END
WITH collect(p2) AS colp2
WITH colp2[0] AS master, colp2[1..] AS others
UNWIND others AS other
MERGE (master)-[:HAS_ALIAS]->(other);
I use MERGE to avoid duplicate relationships.
By the way, just because two people have the same surname and live at the same address, that does not normally mean they are the same person. I hope you are sure that what you are doing is appropriate.