neo4j how to work with two match - neo4j

I have two queries.
First query is
match (user)-[r:CreatesChat]-(chatitems)
Second query is
match (chatitems)-[r:PartOf]-(teamschat)-[s:OwnedBy]-()
I want to return the first 3 users from the first query
And to return the first 3 teams from the second query
The goal is to check if users from first query have the teams of second query
My neo4j query is
match (user)-[r:CreatesChat]-(chatitems)
with user.id as uid,chatitems.id as chatid
order by uid desc
with collect([uid])[..3] as users,collect([chatid])[..3] as chats
UNWIND users AS idusers
match (chatitems)-[r:PartOf]-(teamschat)-[s:OwnedBy]-()
return idusers
This query return
Returned 133239 rows in 1360 ms, displaying first 1000 rows
But I execute the query
match (user)-[r:CreatesChat]-(chatitems)
with user.id as uid,chatitems.id as chatid
order by uid desc
with collect([uid])[..3] as users,collect([chatid])[..3] as chats
UNWIND users AS idusers
return idusers
idusers returned are right
Returned 3 rows in 539 ms.
How can I relate these two queries ?

I think you want to collect both the top 3 users and the top 3 teams and then unwind over each collection. Something like this:
MATCH (user:User)-[:CreatesChat]->(chatitems:Chat)
WITH user ORDER BY user.id DESC LIMIT 3
WITH collect(user) AS users
MATCH (chatitems:Item)-[:PartOf]->(teamsChat:Team)-[:OwnedBy]-()
WITH users, teamsChat ORDER BY teamsChat.id DESC LIMIT 3
WITH users, collect(teamsChat) AS teams
UNWIND users AS user
UNWIND teams AS team
MATCH p=(chatitems:Item)-[:PartOf]-(team)-[:OwndedBy]-(user)
RETURN p

Related

Difference between the results of two independent queries neo4j

I have 2 subqueries that returns 2 sets of users (each query return one set of users)
First query :
MATCH (:User {user_id: "69b3315a-ba4a-4021-94e1-0f494f9b957f"})-->(first_set_of_users)
RETURN first_set_of_users
Second query :
MATCH (:User {user_id: "69b3315a-ba4a-4021-94e1-0f494f9b957f"})<-[:LIKES]-(likers)-[:LIKES]->(v)
WITH DISTINCT v
MATCH (second_set_of_users)-[:LIKES]->(v)
RETURN second_set_of_users, COUNT(*) AS recoWeight
ORDER BY recoWeight DESC
What I want to finally return is all users from second_set_of_users minus the one in first_set_of_users and ORDER BY recoWeight DESC
How can I do that in just one query ? Everything I tried led to cartesian products of queries and took forever while each independent query takes less than a second.
MATCH (:User {user_id: "69b3315a-ba4a-4021-94e1-0f494f9b957f"})-->(first_set_of_users)
WITH collect(first_set_of_users) AS list_of_first_set_of_users
MATCH (:User {user_id: "69b3315a-ba4a-4021-94e1-0f494f9b957f"})<-[:LIKES]-(likers)-[:LIKES]->(v)
WITH DISTINCT v, list_of_first_set_of_users
MATCH (second_set_of_users)-[:LIKES]->(v)
WITH second_set_of_users, COUNT(*) AS recoWeight
WHERE NOT second_set_of_users IN list_of_first_set_of_users
RETURN second_set_of_users, recoWeight
ORDER BY recoWeight DESC
Explanation.
Using WITH clause we could pass the result of the first query into the second query.
And then using WHERE NOT IN we could filter the result of the second query.

Neo4j match don't return rows

I work with neo4j cypher
I have two relations
MATCH (user)-[:CreatesChat]-(chatitems)
MATCH (chatitems)-[:PartOf]->(teamsChat)-[:OwnedBy]-()
With the first query I got the users and chatitems.
And with the second query I got the teams.
I want to check if the users first query have the teams of the second query.
I wrote this query
MATCH (user)-[:CreatesChat]-(chatitems)
WITH user as users ,chatitems as chats ORDER BY chatitems.id DESC LIMIT 10
WITH users,collect(chats) AS chats1
with users, chats1, collect(users) as users1
MATCH (chatitems)-[:PartOf]->(teamsChat)-[:OwnedBy]-()
WITH users1, chats1,teamsChat ORDER BY teamsChat.id DESC LIMIT 3
WITH users1, chats1, collect(teamsChat) AS teams
UNWIND teams AS team
UNWIND chats1 AS chatid
unwind users1 as userid
return userid, chatid, team
Results are
userid,chatid,team
"{""id"":789}","{""id"":65090}","{""id"":62531}"
"{""id"":789}","{""id"":65090}","{""id"":62531}"
"{""id"":656}","{""id"":65092}","{""id"":62531}"
To check if users have the teams of second match, I added
MATCH (user)-[:CreatesChat]-(chatitems)
WITH user as users ,chatitems as chats ORDER BY chatitems.id DESC LIMIT 10
WITH users,collect(chats) AS chats1
with users, chats1, collect(users) as users1
MATCH (chatitems)-[:PartOf]->(teamsChat)-[:OwnedBy]-()
WITH users1, chats1,teamsChat ORDER BY teamsChat.id DESC LIMIT 3
WITH users1, chats1, collect(teamsChat) AS teams
UNWIND teams AS team
UNWIND chats1 AS chatid
unwind users1 as userid
MATCH p=(chats)-[:PartOf]-(teams)-[:OwndedBy]-(users)
RETURN p
This query returns no rows.
How do I have to use the users1,chats1 and team that I got before in MATCH
MATCH p=(chats)-[:PartOf]-(teams)-[:OwndedBy]-(users)
EDITED:
I checked some queries.
I have the query(chatitems and teams)
MATCH (chatitems1)-[:PartOf]->(teamsChat)-[:OwnedBy]-()
WITH chatitems1 , teamsChat ORDER BY teamsChat.id DESC LIMIT 3
return chatitems1,teamsChat
chatitems1,teamsChat
"{""id"":64990}","{""id"":62531}"
"{""id"":63247}","{""id"":62531}"
"{""id"":60211}","{""id"":58852}"
After I executed the query
MATCH (user)-[:CreatesChat]-(chatitems)
WITH user ORDER BY user.id DESC LIMIT 10
MATCH (chatitems1)-[:PartOf]->(teamsChat)-[:OwnedBy]-()
WITH user,chatitems1 , teamsChat ORDER BY teamsChat.id DESC LIMIT 3
return user,chatitems1,teamsChat
I want to see users query 1 and chatitems, teamsChats query 2. The result is
user,chatitems1,teamsChat
"{""id"":65098}","{""id"":64990}","{""id"":62531}"
"{""id"":65098}","{""id"":63247}","{""id"":62531}"
"{""id"":65097}","{""id"":64990}","{""id"":62531}"
Do neo4j a product cartesian?

Trying a single Neo4j Cypher query for my graph

I have "users" who owns "items", users are also friends w/ each other. I am trying to construct a cypher query to return all items I own PLUS those my friends own in a single query. I can do them individually but can't figure out how to do it in a single query.
RELATIONSHIPS:
(u:user)-[:OWNS]-(i:items)
(u:user)-[:FRIEND]-(f:user)
Let's say I have just two users in my DB and 100 items. Out of 100, the first person owns (1-5) 5 items and the 2nd person owns another 5 items(6-10). These two users are also friends.
I get 5 items if I do:
MATCH (uer1)-[:OWNS]->(i:items) return i
I get another 5 items if I do:
MATCH (uer1)-[:FRIEND]->(f)-[:OWNS]->(i:items) return i
But I need to combine them both for a given user(user1) so I can return all 10 items in a single shot. How to do that?
You have two (or more options)
Union
MATCH (user:User {name:"Raja"})-[:OWNS]->(i:Item) return i
UNION
MATCH (user:User {name:"Raja"})-[:FRIEND]->(f)-[:OWNS]->(i:Item) return i
Variable length paths
MATCH (user:User {name:"Raja"})-[:FRIEND*0..1]->(f)-[:OWNS]->(i:Item) return i
in this case we look at friends of the distance 0 (the user itself) to one (first degree friends)
The first option might be faster
The second is more versatile.

How to group and count relationships in cypher neo4j

How can I quickly count the number of "posts" made by one person and group them by person in a cypher query?
Basically I have message label nodes and users that posted (Relationship) those messages. I want to count the number of messages posted by each user.
Its a group messages by sender ID and count the number of messages per user.
Here is what I have so far...
START n=node(*) MATCH (u:User)-[r:Posted]->(m:Message)
RETURN u, r, count(r)
ORDER BY count(r)
LIMIT 10
How about this?
MATCH (u:User)-[r:POSTED]->(m:Message)
RETURN id(u), count(m)
ORDER BY count(m)
Have you had a chance to check out the current reference card?
https://neo4j.com/docs/cypher-refcard/current/
EDIT:
Assuming that the relationship :POSTED is only used for posts then one could do something like this instead
MATCH (u:User {name: 'my user'})
RETURN u, size((u)-[:POSTED]->())
This is significantly cheaper as it does not force a traversal to the actual Message.

Distinct nodes in multiple MATCH query

I have a movie database with users rating movies. I want to find the top 5 most similar users to user 1 (first MATCH which works fine) and recommend him the top rated movies watched by those similar users but not watched by user 1. I get the same movie multiple times even though I have "distinct" in my query. What am I doing wrong?
MATCH (target_user:User {id : 1})-[:RATED]->(m:Movie)
<-[:RATED]-(other_user:User)
WITH other_user, count(distinct m.title) AS num_common_movies, target_user
ORDER BY num_common_movies DESC
LIMIT 5
MATCH other_user-[rat_other_user:RATED]->(m2:Movie)
WHERE NOT (target_user-[:RATED]->m2)
WITH distinct m2.title as movietitle, rat_other_user.note AS rating,
other_user.id AS watched_by
RETURN movietitle, rating, watched_by
ORDER BY rating DESC
You dataset probably has many users who have watched and rated the same movies. When you execute that DISTINCT statement it is going to return a distinct row, not a distinct movie title. Different users will have rated the unwatched movies differently and have different names.
You will have to tune this for your particular use case but you can start from:
MATCH (target_user:User { uid : 1 })-[:RATED]->(m:Movie)<-[:RATED]-(other_user:User)
WITH other_user, count(DISTINCT m.title) AS num_common_movies, target_user
ORDER BY num_common_movies DESC
LIMIT 5
MATCH other_user-[rat_other_user:RATED]->(m2:Movie)
WHERE NOT (target_user-[:RATED]->m2)
RETURN DISTINCT m2.name AS movietitle, COLLECT(rat_other_user.note) AS ratings,
MAX(rat_other_user.note) AS maxi, AVG(rat_other_user.note) as aver, COLLECT(other_user.name) AS users
ORDER BY aver DESC
I added a console demo here.
Importantly the you are now aggregating your results per movie title.

Resources