I have a (:User) dense node with following relationships:
(:User)-[:SUBSCRIBED]->(:User)
(:User)-[:CONNECTED]->(:SocialNetwork)
If I execute query below
MATCH (u:User {UserId:id})
MATCH (u)-[:SUBSCRIBED]->(s)
RETURN s
I get user's subscribers ordered by recent which is expected.
But the same query with additional matching pattern brakes this ordering
MATCH (u:User {UserId:id})
MATCH (u)-[:SUBSCRIBED]->(s)
OPTIONAL MATCH (s)-[:CONNECTED]->(sn)
RETURN s, COUNT(sn.FriendCount)
Could someone explain why ordering by recent doesn't work in the second example.
There is no guarantee of order in your query because you don't have an ORDER clause, run the same query 1000 times and I'm sure the order will change at some point.
You should order at the end of the query :
MATCH (u:User {UserId:id})
MATCH (u)-[:SUBSCRIBED]->(s)
OPTIONAL MATCH (s)-[:CONNECTED]->(sn)
RETURN s, COUNT(sn.FriendCount)
ORDER BY s.time // ? property representing the time
Related
How can I know how many nodes and edges are involved in a MATCH? Is there another way besides Explain / Profile Match?
If you mean how many nodes are matched in a path, such as a variable-length path, then you can assign a path variable for this:
MATCH p = (k:Person {name:'Keanu Reeves'})-[*..8]-(t:Person {name:'Tom Hanks'})
WITH p LIMIT 1
RETURN p, length(p) as pathLength, length(p) + 1 as numberOfNodesInPath
You can also use nodes(p) and relationships(p) to get the collection of nodes and relationships that make up the path, and you can use size() on those collections to get their size.
There exists the COUNT() function of Cypher that allows you to count the number of elements. As for example in this query:
MATCH (n)
RETURN COUNT(n);
This query will count all nodes in your database.
You can find more information in the cypher manual, under the aggregating functions. Check it out.
The following Cypher snippet should return the number of distinct nodes and relationships found by any given MATCH clause. Just replace <your code here> with your MATCH pattern.
MATCH <your code here>
WITH COLLECT(NODES(p)) AS ns, SUM(SIZE(RELATIONSHIPS(p))) AS relCount
UNWIND ns AS nodeList
UNWIND nodeList AS node
RETURN COUNT(DISTINCT node) AS nodeCount, relCount;
So as a complication to this question, I basically want to do
MATCH (n:TEST) OPTIONAL MATCH (n)-[r]->() RETURN DISTINCT n, r
And I want to return n and r as one column with no repeat values. However, running
MATCH (n:TEST) OPTIONAL MATCH (n)-[r]->() UNWIND n+r AS x RETURN DISTINCT x
gives a "Type mismatch: expected List but was Relationship (line 1, column 47)" error. And this query
MATCH (n:TEST) RETURN DISTINCT n UNION MATCH ()-[n]->() RETURN DISTINCT n
Puts nodes and relationships in the same column, but the context from the first match is lost in the second half.
So how can I return all matched nodes and relationships as one minimal list?
UPDATE:
This is the final modified version of the answer query I am using
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r {properties:properties(r), id:id(r), type:type(r), startNode:id(startNode(r)), endNode:id(endNode(r))})} as n
There are a couple ways to handle this, depending on if you want to hold these within lists, or within maps, or if you want a map projection of a node to include its relationships.
If you're using Neo4j 3.1 or newer, then map projection is probably the easiest approach. Using this, we can output the properties of a node and include its relationships as a collected property:
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r)} as n
Here's what you might do if you wanted each row to be its own pairing of a node and a single one of its relationships as a list:
...
RETURN [n, r] as pair
And as a map:
...
RETURN {node:n, rel:r} as pair
EDIT
As far as returning more data from each relationship, if you check the Code results tab, you'll see that the id, relationship type, and start and end node ids are included, and accessible from your back-end code.
However, if you want to explicitly return this data, then we just need to include it in the query, using another map projection for each relationship:
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r {.*, id:id(r), type:type(r), startNode:startNode(r), endNode:endNode(r)})} as n
NOT RELEVANT - SKIP TO Important Edit.
I have the following query:
MATCH (n)
WHERE (n:person) AND n.id in ['af97ab48544b'] // id is our system identifier
OPTIONAL MATCH (n)-[r:friend|connected|owner]-(m)
WHERE (m:person OR m:dog OR m:cat)
RETURN n,r,m
This query returns all the persons, dogs and cats that have a relationship with a specific person. I would like to turn it over to receive all the nodes & relationships that NOT includes in this query results.
If it was SQL it would be
select * from graph where id NOT IN (my_query)
I think that the OPTIONAL MATCH is the problematic part. I How can I do it?
Any advice?
Thanks.
-- Important Edit --
Hey guys, sorry for changing my question but my requirements has been changed. I need to get the entire graph (all nodes and relationships) connected and disconnected except specific nodes by ids. The following query is working but only for single id, in case of more ids it isn't working.
MATCH (n) WHERE (n:person)
OPTIONAL MATCH (n)-[r:friend|connected|owner]-(m) WHERE (m:person OR m:dog OR m:cat)
WITH n,r,m
MATCH (excludeNode) WHERE excludeNode.id IN ['af97ab48544b']
WITH n,r,m,excludeNode WHERE NOT n.id = excludeNode.id AND (NOT m.id = excludeNode.id OR m is null)
RETURN n,m,r
Alternatively I tried simpler query:
MATCH (n) WHERE (n:person) AND NOT n.id IN ['af97ab48544b'] return n
But this one does not returns the relationships (remember I need disconnected nodes also).
How can I get the entire graph exclude specific nodes? That includes nodes and relationships, connected nodes and disconnected as well.
try this:
match (n) where not n.id = 'id to remove' optional match (n)-[r]-(m)
where not n.id in ['id to remove'] and not m.id in ['id to remove']
return n,r,m
You've gotta switch the 'perspective' of your query... start by looping over every node, then prune the ones that connect to your person.
MATCH (bad:person) WHERE bad.id IN ['af97ab48544b']
WITH COLLECT(bad) AS bads
MATCH path = (n:person) - [r:friend|:connected|:owner] -> (m)
WHERE n._id = '' AND (m:person OR m:cat OR m:dog) AND NOT ANY(bad IN bads WHERE bad IN NODES(path))
RETURN path
That said, this is a problem much more suited to SQL than to a graph. Any time you have to loop over every node with a label, you're in relational territory, the graph will be less efficient.
I search the longest path of my graph and I want to count the number of distinct nodes of this longest path.
I want to use count(distinct())
I tried two queries.
First is
match p=(primero)-[:ResponseTo*]-(segundo)
with max(length(p)) as lengthPath
match p1=(primero)-[:ResponseTo*]-(segundo)
where length(p1) = lengthPath
return nodes(p1)
The query result is a graph with the path nodes.
But if I tried the query
match p=(primero)-[:ResponseTo*]-(segundo)
with max(length(p)) as lengthPath
match p1=(primero)-[:ResponseTo*]-(segundo)
where length(p1) = lengthPath
return count(distinct(primero))
The result is
count(distinct(primero))
2
How can I use count(distinct()) over the node primero.
Node Primero has a field called id.
You should bind at least one of those nodes, add a direction and also consider a path-limit otherwise this is an extremely expensive query.
match p=(primero)-[:ResponseTo*..30]-(segundo)
with p order by length(p) desc limit 1
unwind nodes(p) as n
return distinct n;
I am using the following query to get user status updates and total likes each have received:
MATCH (n:user {username: "pewpewlasers"})-[:STATUSUPDATE|:NEXT*]->(o)
OPTIONAL MATCH (p:user)-[x:LIKED]->(o)
RETURN n, o, COUNT(p) AS totallikes
ORDER BY o.date DESC SKIP 0 LIMIT 10
This works great, but now I want to also get information on whether a particular user has liked these status updates (to implement 'unlike' feature). I tried the following and it is giving me big (wrong) numbers, even the totallikes
MATCH (n:user {username: "pewpewlasers"})-[:STATUSUPDATE|:NEXT*]->(o)
OPTIONAL MATCH (p:user)-[:LIKED]->(o)
OPTIONAL MATCH (q:user {username: "anotherUser"})-[:LIKED]->(o)
RETURN n, o, COUNT(p) AS totallikes, COUNT(q) AS hasLiked
ORDER BY o.date DESC SKIP 0 LIMIT 10
EDIT: The graph looks like the following (orange nodes -> user nodes, gray nodes -> status update nodes):
Your 2 OPTIONAL MATCH clauses are essentially identical, except for the username qualification in the second one. Therefore, logically, it should be possible for a single relationship to match both clauses. However, according to the neo4j manual:
While pattern matching, Cypher makes sure to not include matches where
the same graph relationship is found multiple times in a single
pattern.
It is possible that this is causing the number of matches to be too low.
Does the following work better for you?
[EDITED]
MATCH (n:user {username: "pewpewlasers"})-[:STATUSUPDATE|:NEXT*]->(o)
OPTIONAL MATCH (p:user)-[:LIKED]->(o)
WITH n, o, COLLECT(p) AS cp
RETURN n, o, length(cp) AS totallikes, length(filter(x IN cp WHERE x.username="anotherUser")) AS hasLiked
ORDER BY o.date DESC LIMIT 10