cypher query get wrong results - neo4j

I have a graph which contains 3 types of nodes : Post, User, Cat, every cat have so many posts that are linked together with a 'next' relationship, every user can comment on these posts and the comment is a 'Commented' relationship with a 'content' and 'id' property.
I want to get the posts of some cat and all the comments related to every post.
I've tried this but it don't give me posts without comments:
MATCH (cat:Cat {id:1})-[:lastPost]->(last)-[:next*0..]->(rest)
MATCH (rest)<-[c:Commented]-(u:User)
RETURN c, rest
Is there any way to achieve what I want in Cypher ? thank you

Try changing the second MATCH statement to an OPTIONAL MATCH:
MATCH (cat:Cat {id:1})-[:lastPost]->(last)-[:next*0..]->(rest)
OPTIONAL MATCH (rest)<-[c:Commented]-(u:User)
RETURN c, rest
Any values that don't match the OPTIONAL MATCH pattern will be NULL.

Related

how to gather the unique related rows in a neo4j cypher query?

I have 3 posts, 1 of which has two comments. I need to retrieve the 3 post plus the 2 comments and the authors. Problem is cypher returns all the associated links. How can I get only the rows I need? When run this query I get 72 rows....I am only expecting 4 rows:
MATCH (p:Posts)
WITH p
MATCH(c:Comments)-[r:COMMENTED_ON]-()
WITH p, c
MATCH (u)-[:MADE_A_POST]->()
WITH p,c,u
MATCH (n)-[:POSTED_COMMENT]-()
RETURN {post:p,comments:c,author:u,commentator:n}
I am trying to ensure that each row only contain the properties related to that row. In this case I should have 4 rows...since one of the post has 2 comments. I looked at UNION, COLLECT and DISTINCT and none seems to be a good fit. Any help would be appreciated.
In your query you are effectively doing the following:
Match all posts
Match all comments that have a COMMENTED_ON relationship
MATCH all nodes that have a MADE_A_POST relationship
MATCH all nodes that have POSTED_COMMENT relationship
As I don't have sight of your data model, I can only guess, but it looks like you're making no direct connection between posts with comments, and then finding the authors of those.
Taking a guess, I think your query should look like the following:
MATCH (p:Posts)
WITH p
MATCH (n)-[:POSTED_COMMENT]-(c:Comments)-[r:COMMENTED_ON]-(p)
MATCH (u)-[:MADE_A_POST]->(p)
RETURN {post:p,comments:c,author:u,commentator:n}

How to get counts of Edges related to a node in one query - NEO4J

I have two questions.
What is the best way to index user activities like posts, reposts, comments, upvotes, and downvotes. My current solution is representing every activity as a POST. It should work, but I know its quite expensive to regard upvotes and downvotes as new nodes when I can just use a relationship to represent this. But then, I want to be able to fetch everything once and order.
Secondly: When I run the following excluding the WITH and following MATCH, The result is larger but as I try to get the counts of reposts, replies and upvotes. The result keeps getting smaller and eventually nothing.
MATCH (me:User {id: "172ed572-e3af-d3ee-77c0-8d9d181b12f1"})-[:COLLEAGUE_OF]-(u:User)-[posted:POSTED]->(p:Post) WHERE posted.date >= 0
WITH p, posted, u AS user MATCH (p)-[ro:REPOST_OF]-(:Post)
WITH count(ro) AS reposts, posted, ro, user MATCH (p)-[rt:REPLY_TO]->(:Post)
WITH count(rt) AS replies, posted, user, reposts MATCH (p)-[uv:UP_VOTE]->(:Post)
WITH count(uv) AS upvotes, posted, user, reposts, replies, p
RETURN p AS post, posted, user, reposts, replies
ORDER BY -posted.date
You need to read the documentation on aggregating functions (like COUNT). In particular, you need to understand that the WITH (and RETURN) clause treats terms that do not contain aggregating functions as the "grouping keys" for the terms that do contain aggregating functions.
For example, a clause such as WITH foo, COUNT(foo) AS fooCount will always produce a fooCount of 1.
WITH clauses must specify the bound variables whose values you want to use later in the same query; any unspecified variables will be dropped. SInce your second and third WITH clauses do not specify p, their subsequent MATCH clauses are actually NOT using the previously bound value for p (but creating totally new p variables, each having multiple values).
You should use OPTIONAL MATCH instead of MATCH to get the counts of things that may not exist. A MATCH would cause the entire query to abort if it fails to find a match.
You neglected to make the (p)-[ro:REPOST_OF]-(:Post) relationship pattern directional. If you wanted to get a count of the number of times that p was reposted, so you should have used the pattern (p)<-[ro:REPOST_OF]-(:Post).
You forgot to return upvotes.
You should use ORDER BY posted.date DESC instead of ORDER BY -posted.date.
This may work better for you:
MATCH (:User {id: "172ed572-e3af-d3ee-77c0-8d9d181b12f1"})-[:COLLEAGUE_OF]-(user:User)-[posted:POSTED]->(p:Post)
WHERE posted.date >= 0
OPTIONAL MATCH (p)<-[ro:REPOST_OF]-(:Post)
WITH p, posted, user, COUNT(ro) AS reposts
OPTIONAL MATCH (p)-[rt:REPLY_TO]->(:Post)
WITH p, posted, user, reposts, COUNT(rt) AS replies
OPTIONAL MATCH (p)-[uv:UP_VOTE]->(:Post)
RETURN p, posted, user, reposts, replies, COUNT(uv) AS upvotes
ORDER BY posted.date DESC

Neo4j Cypher query - relationship with an "or"

I'm trying to get a named relationship with an or in the query. I'm thinking the query should look similar to:
MATCH (A:person)-[B (:ACTED_IN|:DIRECTED)]->(C:person) RETURN A, B, C
but no matter how I put in the parens I get an error. I suppose a UNION would do the trick but was hoping that there was some way of doing it similar to the above. TIA.
EDIT: This does what I want but seems not the way to do it.
MATCH (A:person)-[B]->(C:person) WHERE type(B)="ACTED_IN" OR type(B)="DIRECTED" RETURN A,B,C
I am a new user so I do not have the option to comment on questions yet. I am guessing you are trying to get the person who either acted in or directed the movie. Its described in official Cypher Documentation: Match on multiple relationship types.
With Demo Movie Data on Neo4j to get persons from The Matrix movie, I would use this:
MATCH (TheMatrix { title: 'The Matrix' })<-[rel:ACTED_IN|:DIRECTED]-(person)
RETURN person.name, rel

Cypher returning multiple rows per match

I am querying neo4j with cypher and am getting two rows per match:
MATCH (g:Group {Name: "Goliath_Treasury237"})-[w:MEMBER]->(a:Account)<-[y:ACCOUNT]-(p:Person)-[MANAGER*0..1]->(b:Person)
WHERE NOT p.staffID = b.staffID
MATCH (g:Group {Name: "Goliath_Treasury237"})-[j:MEMBER]->(v:Account)<-[x:ACCOUNT]-(p:Person)-[f:DEP*0..1]->(d:Department)
RETURN p.GivenName, p.Surname, p.staffID, p.CorpT, b.staffID, d.Name
I'm trying to get the information for both the department and the boss of a person which I'm struggling with declaratively unless I do the double match. This returns two rows for each match where a person has a boss, one with their ID as their bosses ID and one with the correct bosses id. For people without a boss I get one row back but the bosses id is their own.
If I remove the variable length path for boss then I get one row for each individual but no row where someone doesn't have a boss.
I'm at a loss now, any help would be great!
There's several things we can fix here.
For one, you don't need the second match to start over from the beginning, you can reuse the same p node without needing all the stuff before. You also don't need to have a variable on every node and relationship if you're not going to use or return it in some way.
You can use an OPTIONAL MATCH when you don't want the match to filter out rows, newly-introduced variables in the OPTIONAL MATCH will be null if the match fails.
Something like this should work:
MATCH (:Group {Name: "Goliath_Treasury237"})-[:MEMBER]->(:Account)<-[:ACCOUNT]-(p:Person)
OPTIONAL MATCH (p)-[MANAGER]->(b:Person)
WHERE NOT p.staffID = b.staffID
OPTIONAL MATCH (p)-[:DEP]->(d:Department)
RETURN p.GivenName, p.Surname, p.staffID, p.CorpT, b.staffID, d.Name

how to use two match statements in a cypher query

I'd like to combine two requests into one query and I'm not sure what happens when 2 match statements are used in a single cypher query.
say I have a list of friends and I'd like to see a list of my friends with each of their uncles and siblings listed in a collection. Can I have two match statements that would do the job? e.g.
match friends-[:childOf]->parents-[:brother]->uncles
, friends-[:childOf]->parents<-[:childOf]-siblings
return friends, collect(siblings), collect(uncles)
However, if I do a query like this, it always returns no results.
Since you have already chosen parents in your first match class, you can do like this -
match friends-[:childOf]->parents-[:brother]->uncles
with friends, parents, uncles
match parents<-[:childOf]-siblings
return friends, collect(siblings), collect(uncles)
You may want to make some of those relationships optional. For example, if you find a sibling but you don't find any uncles, this query will return null because it didn't satisfy both match clauses. If you make the end relationships optional then you don't have to satisfy both clauses completely to return data. So:
match friends-[:childOf]->parents-[?:brother]->uncles
, friends-[:childOf]->parents<-[?:childOf]-siblings
return friends, collect(siblings), collect(uncles)

Resources