Can Neo4j Cypher query do similar thing as "Having" in SQL? - neo4j

SQL has "Having" clause, for example:
SELECT LastName, COUNT(*)
FROM Employees
GROUP BY LastName
HAVING COUNT(*) > 10;
In Cypher, we can do count()
START n=node(2)
MATCH (n)-[r]->()
RETURN type(r), count(*)
But does Cypher have similar function as "Having", or is there any workaround?

Sure, having is just one of the many uses of query chaining with WITH which is similar to RETURN but determines which elements will be available in the next query part. WITH also supports ordering and paging.
START n=node(2)
MATCH (n)-[r]->()
WITH type(r) as t, count(*) as c
WHERE c > 10
RETURN t,c

Related

Get the count of multiple properties in neo4j

I am trying to combine 2 cyphers into one for performance but have not succeeded.
I need to get the count of multiple properties unique to eachother in the same cypher.
EX 1:
Match (n)
RETURN n.foo, count(*) AS count
EX 2:
Match (n)
RETURN n.bar, count(*) AS count
I was hoping I could just run both:
Match (n)
RETURN n.foo, count(*) AS fooCount, n.bar, count(*) AS barCount
But this returns the same count for both as it is finding where they both match. Not what I want.
So was looking for a way to group them to be unique like:
Match (n)
RETURN {n.foo, count(*) AS fooCount}, {n.bar, count(*) AS barCount}
Obviously this is not valid syntax but shows what I am trying to do.
Any assistance on this is of course appreciated.
It's best to do this back to back, all at once isn't a good idea for this kind of query, as aggregation won't work in your favor.
You could try this:
MATCH (n)
WITH n.bar as bar, count(*) AS count
WITH collect({bar:bar, count:count}) as barCounts
MATCH (n)
WITH barCounts, n.foo as foo, count(*) AS count
WITH barCounts, collect({foo:foo, count:count}) as fooCounts
RETURN barCounts, fooCounts
Since you are trying to aggregate separate query results, you can also use UNION as a quick and easy way to return both at the same time.
Match (n)
RETURN "foo" as type, n.foo as value, count(*) AS count
UNION ALL
Match (n)
RETURN "bar" as type, n.bar as value, count(*) AS count
Just a few notes, both returns for a UNION must have the same column names.
Also, the "type" column in the example isn't necessary, but it shows how you can add filler if both queries don't have the same number of return columns. (Or if you want to tell which query the result is from.) If there is a "foo" and a "bar" with the same value+count, UNION ALL will keep both, and UNION will drop the duplicate (if you remove the type column).
Maybe it's outdated, but just in case someone needs it, I've found another approach using an APOC function which avoids running multiple times the same MATCH (n). In your case, it could be something like:
MATCH (n)
WITH collect(n.bar) as bars, collect(n.foo) as foos
WITH apoc.coll.frequenciesAsMap(bars) as barCounts, apoc.coll.frequenciesAsMap(foos) as fooCounts
RETURN barCounts, fooCounts
Single MATCH, multiple Counts.
Wish it could help someone!

How to count the total number of relations in neo4j?

I am trying the following query,
start n=node(*) match (n)-[r]->(m) return count(r)
I am not sure if this query is fine.
You should use this query : MATCH ()-[r]->() RETURN count(*)
Cheers.
PS: The start, match query form should be only used for legacy index.
Try this query to count the number of relationships :
MATCH ()-[r:NAME_OF_RELATIONSHIP]->() RETURN count(r)

Returning subquery in neo4j based on two different where conditions

I have this query in SQL:
Select Id, CrawlerId,CrawlerName,
(SELECT Count(*) from CrawlerResult cr where cr.CrawlerId = cs.CrawlerId and IsNew=1) as LastRunResult ,
(SELECT Count(*) from CrawlerResult cr where cr.CrawlerId = cs.CrawlerId ) as TotalResult
FROM CrawlerScheduler cs
How to convert this query to neo4j cypher by combining CrawlerScheduler and CrawlerResult nodes?
I'm assuming you've replaced the foreign key relationships from SQL with actual relationships in Cypher, and that you're using actual booleans instead of 1 and 0? Something like:
(:CrawlerScheduler)-[:RESULT]->(:CrawlerResult)
If so then the equivalent Cypher query might look like this:
MATCH (cs:CrawlerScheduler)
WITH cs, SIZE((cs)-[:RESULT]->()) as TotalResult
OPTIONAL MATCH (cs)-[:RESULT]->(cr)
WHERE cr.IsNew
WITH cs, TotalResult, COUNT(cr) as LastRunResult
RETURN cs.Id, cs.CrawlerId, cs.CrawlerName, LastRunResult, TotalResult
EDIT
I changed the second match to an OPTIONAL MATCH, just in case the scheduler didn't have results, or didn't have new results.

Cypher group by subquery syntax

I need to do an aggregation on an aggregation in Cypher on Neo4j;
match (
match (w:words)
return distinct k.word as word, count(w) as count, count(distinct w.id) as id
) as a
return distinct id, count(word), sum(count);
Is this possible, google suggests not?
Try something like this using with:
match (w:words)
with distinct w.word as word, count(w) as count, count(distinct w.id) as id
return distinct id, count(word), sum(count);

Limit the results of a union cypher query

Let's say we have the example query from the documentation:
MATCH (n:Actor)
RETURN n.name AS name
UNION
MATCH (n:Movie)
RETURN n.title AS name
I know that if I do that:
MATCH (n:Actor)
RETURN n.name AS name
LIMIT 5
UNION
MATCH (n:Movie)
RETURN n.title AS name
LIMIT 5
I can reduce the returned results of each sub query to 5.How can I LIMIT the total results of the union query?
This is not yet possible, but there is already an open neo4j issue that requests the ability to do post-UNION processing, which includes what you are asking about. You can add a comment to that neo4j issue if you support having it resolved.
This can be done using UNION post processing by rewriting the query using the COLLECT function and the UNWIND clause.
First we turn the columns of a result into a map (struct, hash, dictionary), to retain its structure. For each partial query we use the COLLECT to aggregate these maps into a list, which also reduces our row count (cardinality) to one (1) for the following MATCH. Combining the lists is a simple list concatenation with the “+” operator.
Once we have the complete list, we use UNWIND to transform it back into rows of maps. After this, we use the WITH clause to deconstruct the maps into columns again and perform operations like sorting, pagination, filtering or any other aggregation or operation.
The rewritten query will be as below:
MATCH (n:Actor)
with collect ({name: n.title}) as row
MATCH (n:Movie)
with row + collect({name: n.title}) as rows
unwind rows as row
with row.name as name
return name LIMIT 5
This is possible in 4.0.0
CALL {
MATCH (p:Person) RETURN p
UNION
MATCH (p:Person) RETURN p
}
RETURN p.name, p.age ORDER BY p.name
Read more about Post-union processing here https://neo4j.com/docs/cypher-manual/4.0/clauses/call-subquery/

Resources