I have a query in cypher , I create a relationship between :
MATCH match (u:user {id : "10662"})-[r:has_profile]->(p:profile)
, (u2:user)-[r2:has_profile]->(p2:profile)
WHERE
p.user_id <> p2.user_id
AND abs(u2.date_birth - u.date_birth) >= 94608000000
merge u-[r:matches_with { weight: rand() }]->u2
RETURN collect(u2.id) as id;
In this particular situation, I am trying to create a relationship between u and u2 only on a match, when a previous relationship between u and u2 is found. It will just increment the weight in the relationship.
And I am trying to return the matches based on weight.
Can someone please suggest an approach for incrementing the weight on finding a match, with this query. Thank you.
Here is a query that looks for all matches_with relationships starting from a specific user, increments the weight of the relationship, and returns the results sorted by weight.
MATCH (u:user { id : "10662" })-[r:matches_with]->(u2)
SET r.weight = r.weight + 1
RETURN u, r, u2
ORDER BY r.weight;
I found a mechanism , by which you can alter the weight..
I added the merge clause before the return statement:
MATCH (u:user { id : "10662" })-[r:matches_with]->(u2)
merge (u)-[m:matches_with]->(u2)
SET m.weight=
CASE WHEN NOT (HAS (m.weight))
THEN toFloat(0.125)
ELSE LAST(m.weight)/2
END
RETURN u.id, m, u2.id
ORDER BY m.weight;
Thank you #cybersam.
Related
How can I match using Cypher by any relation amount? For example, in a database there are Person. If this person has any son, they will be related by the relation [:SON].
This query will return each Person that has a son:
match (p:Person)-[:SON]->(:Person)
return p
Knowing this, how can I match the number of Person that only has 2 sons?
You can use size() in the where clause, like so:
match (p:Person) where size((p)-[:SON]->())=2 return p
You can use the count function to get the count of sons for each person. Then filter out the persons based on the count.
MATCH (p:Person)-[r:SON]->(:Person)
WITH p, count(r) as sons
WHERE sons=2
RETURN p
I'm trying to make a cypher query to make nodes list which is using "multi match" as follows:
MATCH (N1:Node)-[r1:write]->(P1:Node),
(P1:Node)-[r2:access]->(P2:Node)<-[r3:create]-(P1)
WHERE r1.Time <r3.Time and r1.ID = r2.ID and r3.Time < r2.Time
return nodes(*)
I expect the output of the Cypher to be all nodes of the result, but Cypher doesn't support nodes(*).
I know that there is a way to resolve this like thisa;
MATCH G1=(N1:Node)-[r1:write]->(P1:Node),
G2=(P1:Node)-[r2:access]->(P2:Node)<-[r3:create]-(P1)
WHERE r1.Time <r3.Time and r1.ID = r2.ID and r3.Time < r2.Time
return nodes(G1), nodes(G2)
But the match part could be changed frequently so I want to know the way to get nodes from multi-match without handling variable for every match.
Is it possible?
Your specific example is easy to consolidate into a single path, as in:
MATCH p=(:Node)-[r1:write]->(p1:Node)-[r2:access]->(:Node)<-[r3:create]-(p1)
WHERE r1.Time < r3.Time < r2.Time AND r1.ID = r2.ID
RETURN NODES(p)
If you want the get distinct nodes, you can replace RETURN NODES(p) with UNWIND NODES(p) AS n RETURN DISTINCT n.
But, in general, you might be able to use the UNION clause to join the results of multiple disjoint statements, as in:
MATCH p=(:Node)-[r1:write]->(p1:Node)-[r2:access]->(:Node)<-[r3:create]-(p1)
WHERE r1.Time < r3.Time < r2.Time AND r1.ID = r2.ID
UNWIND NODES(p) AS n
RETURN n
UNION
MATCH p=(q0:Node)-[s1:create]->(q1:Node)-[s2:read]->(q0)
WHERE s2.Time > s1.Time AND s1.ID = s2.ID
UNWIND NODES(p) AS n
RETURN n
The UNION clause would combine the 2 results (after removing duplicates). UNION ALL can be used instead to keep all the duplicate results. The drawback of using UNION (ALL) is that variables cannot be shared between the sub-statements.
Consider the following DB structure:
For your convenience, you can create it using:
create (p1:Person {name: "p1"}),(p2:Person {name: "p2"}),(p3:Person {name: "p3"}),(e1:Expertise {title: "Exp1"}),(e2:Expertise {title: "Exp2"}),(e3:Expertise {title: "Exp3"}),(p1)-[r1:Expert]->(e1),(p1)-[r2:Expert]->(e2),(p2)-[r3:Expert]->(e2),(p3)-[r4:Expert]->(e3),(p2)-[r5:Expert]->(e3)
I want to be able to find all Person nodes that are not related to a specific Expertise node, e.g. "Exp2"
I tried
MATCH (p:Person)--(e:Expertise)
WHERE NOT (e.title = "Exp2")
RETURN p
But it returns all the Person nodes (while I expected it to return only p3).
Logically, this result makes sense because each of these nodes is related to at least one Expertise that is not Exp2.
But what I want is to find all the Person nodes that are not related to Exp2, even if they are related to other nodes as well.
How can this be done?
Edit
It appears that I wasn't clear on the requirements. This is a (very) simplified way of presenting my problem with a much more complicated DB.
Consider the possibility that Expertise has more properties which I would like to use in the same query (not necessarily with negation). For example:
MATCH (p)--(e)
WHERE e.someProp > 5 AND e.anotherProp = "cookie" AND NOT e.title = "Exp2"
UPDATE
You need to restrict it a bit more, meaning to only the person
MATCH (p:Person), (e:Expertise {title="Exp2"})
WHERE NOT (p)-[]->(e)
RETURN p
I think you will be just fine with the <> operator :
MATCH (p:Person)--(e:Expertise)
WHERE e.title <> "Exp2"
RETURN p
Or you can express it in a pattern :
MATCH (p:Person)
WHERE NOT EXISTS((p)--(e:Expertise {title:"Exp2"}))
RETURN p
Little change query from #ChristopheWillemsen:
MATCH (e:Expertise) WHERE e.someProperty > 5 AND NOT e.title = someValue
WITH collect(e) as es
MATCH (p:Person) WHERE all(e in es WHERE NOT Exists( (p)--(e) ) )
RETURN p
UPDATE:
// Collect the `Expertise` for which the following conditions:
MATCH (e:Expertise) WHERE e.num > 3 AND e.title = 'Exp2'
WITH collect(e) as es
// Select the users who do not connect with any of of expertise from `es` set:
OPTIONAL MATCH (p:Person) WHERE all(e in es WHERE NOT Exists( (p)--(e) ) )
RETURN es, collect(p)
Another query with some optimization:
// Get the set of `Expertise-node` for which the following conditions:
MATCH (e:Expertise) WHERE e.num > 3 AND e.title = 'Exp2'
// Collect all `Person-node` connected to node from the `Expertise-node` set:
OPTIONAL MATCH (e)--(p:Person)
WITH collect(e) as es, collect(distinct id(p)) as eps
//Get all `Person-node` not in `eps` set:
OPTIONAL MATCH (p:Person) WHERE NOT id(p) IN eps
RETURN es, collect(p)
For the cypher -
match (m)-[r]-(n) where m.name = 'XYZ' return n.name, type(r), m.name
n.name type(r) m.name
XYZ belongs_to Ordering Status
XYZ runs_on_queue inbound
XYZ runs_on_db DBxc
In this case, Ordering Status is a business service that "owns" XYZ & the relation is defined as follows:
CREATE (XYZ)-[:belongs_to]->(Order)
Type(r) only gives the relation but not the direction of the relation. Is this still the optimal way to get the direction - I also noticed a comment on not being available for Cypher
Neo4j Cypher Get Relationship Direction
Thanks.
Not as a function, but you can do this:
MATCH (m)-[r]-(n)
RETURN m.name, TYPE(r), n.name,
CASE WHEN STARTNODE(r) = m THEN 'outgoing' ELSE 'incoming' END AS direction
Say I have a pizza menu where each type of pizza is represented as a node with label Pizza, and each topping is a node with label Topping. To get all the pizza's with pepperoni I write the following query
MATCH (p:Pizza)-[:HAS]->(t:Topping{type : "pepperoni"}) return p.
Then say I have a set of users who can specify their favorite pizzas.
MATCH (u:User)-[:HAS_FAVORITE]->(p:Pizza).
What is the best way to find the users who like ALL the pizzas having pepperoni ?
Thanks in advance for your time.
The following method compares the count of the user's favorites having pepperoni with the count of all pizzas with pepperoni. It performs well because it matches using an index and relationship traversals to collect only user favorites having pepperoni. The answer posted by cybersam is slow because it has to do a full scan of all favorites.
MATCH (p:Pizza)-[:HAS]->(t:Topping { type : "pepperoni" })
WITH COUNT(p) AS pCnt, COLLECT(p) AS pCol
UNWIND pCol as pPep
MATCH (u:User)-[:HAS_FAVORITE]->(pPep)
WITH u, COUNT(*) as fCnt, pCnt
WHERE fCnt = pCnt
RETURN u
This is how to find all distinct users who like ANY pizza(s) with pepperoni topping:
MATCH (u:User)-[:HAS_FAVORITE]->(p:Pizza)-[:HAS]->(t:Topping {type : "pepperoni"})
RETURN DISTINCT u;
This is one way to find all distinct users who like ALL pizza(s) with pepperoni topping:
MATCH (p:Pizza)-[:HAS]->(t:Topping { type : "pepperoni" })
WITH COLLECT(p) AS ps
MATCH (u:User)-[:HAS_FAVORITE]->(q:Pizza)
WITH u, COLLECT(q) AS qs, ps
WHERE ALL (x IN ps WHERE x IN qs)
RETURN u;