I have the following db:
CREATE (p1:Product {cost:10, name:'Hrundel'})
CREATE (p2:Product {cost:20, name:'Majora'})
CREATE (p3:Product {cost:30, name:'Elona'})
CREATE (s:Shop {name:'CarsMorpher'})
CREATE s-[:HAS]->(p1)
CREATE s-[:HAS]->(p2)
CREATE s-[:HAS]->(p3)
How can I find the name of the product that has lowest (highest) price?
Use max and min to calculate highest and lowest, and do something like this:
MATCH (p:Product)
WITH max(p.cost) as highestCost
MATCH (p2:Product)
where p2.cost=highestCost
return p2;
Using WITH you can chain the results from the earlier query together with a second query.
A different way of doing it:
MATCH (p:Product) RETURN p
ORDER BY p.cost DESC
LIMIT 1;
So this just lists them in descending order by price, and only gives you one (the maximum)
Related
I have a collection of :Product nodes and I want to return latest 100. Consider global query like:
MATCH (p:Product) RETURN p LIMIT 100
From what I can see it returns oldest nodes first. Is there a way of getting newest on top?
Order by won't be an option as number of products can be millions.
UPDATE
I ended up creating a dense node (:ProductIndex). Each time I create product I add it to the index (:Product)-[:INDEXED]->(:ProductIndex). With dense nodes rel chain will be ordered by latest first so that query below will return newest records on top
MATCH (p:Product)-[:INDEXED]->(:ProductIndex)
RETURN p
LIMIT 1000
I can always keep index fixed size as I don't need to preserve full history.
Is the data model such that the products are connected in a list (e.g. (:Product)-[:PREVIOUS]->(:Product)?
Can you keep track of the most recent node? Either with a time stamp that you can easily locate or another node connected to your most recent product node.
If so, you could always query out the most recent ones with a query similar to the following.
match (max:Date {name: 'Last Product Date'})-->(latest:Product)
with latest
match p=(latest)-[:PREVIOUS*..100]->(:Product)
return nodes(p)
order by length(p) desc
limit 1
OR something like this where you select
match (max:Date {name: 'Product Date'})
with max
match p=(latest:Product)-[:PREVIOUS*..100]->(:Product)
where latest.date = max.date
return nodes(p)
order by length(p) desc
limit 1
Another approach, still using a list could be to keep an indexed create date property on each product. But when looking for the most recent pick a control date that doesn't go back to the beginning of time so you have a smaller pool of nodes (i.e. not millions). Then use an max function on that smaller pool to find the most recent node and follow it back by however many you want.
match (latest:Product)
where latest.date > {control_date}
with max(latest.date) as latest_date
match p=(product:Product)-[:PREVIOUS*..100]->(:Product)
where product.date = latest_date
return nodes(p)
order by length(p) desc
limit 1
Deleting a node in a linked list is pretty simple. If you need to perform this search a lot and you don't want to order the products, I think keeping the products in a list is a pretty good graph application. Here is an example of a delete that maintains the list.
match (previous:Product)<-[:PREVIOUS]-(product_to_delete:Product)<-[:PREVIOUS]-(next:Product)
where product_to_delete.name = 'name of node to delete'
create (previous)<-[:PREVIOUS]-(next)
detach delete product_to_delete
return previous, next
I'm trying to run a query where I assign integers based on the order they appeared in the query. I'd like it to work to the effect of:
MATCH users RETURN users ORDER BY created_at SET user.number=ROW_NUMBER()
Is there a way to do this in a single query? Thanks!
You can do it by playing a bit with a collection :
MATCH (n:User)
WITH n
ORDER BY n.created_at
WITH collect(n) as users
UNWIND range(0, size(users)-1) as pos
SET (users[pos]).number = pos
If I want to perform a MATCH query on the top 25 results of a previous MATCH, how would I do this in Cypher?
My first query is like:
START inputMovie=node(0)
MATCH (inputGenre:Genre)-[:IS_GENRE]-(inputMovie:Movie)
WITH inputMovie, COLLECT(inputGenre) AS inputGenres
MATCH (genre:Genre)-[o:IS_GENRE]-(outMovies:Movie)
WITH inputGenres, outMovies, genre
WHERE (genre IN inputGenres)
RETURN outMovies.title, count(genre) AS foo
ORDER BY foo desc
LIMIT 25
How would I then perform a MATCH query on only those 25 results? Can I collect a number of nodes? COLLECT(m) would collect every single node matching the WHERE constraint. Is there a way to collect the top 25 from a MATCH query?
[EDITED]
First of all, your current query can be improved. The following shorter and faster query should be equivalent (and avoids using the deprecated START clause):
MATCH (outMovie:Movie)-[:IS_GENRE]-(:Genre)-[:IS_GENRE]-(inputMovie:Movie)
WHERE ID(inputMovie) = 0
MATCH (outMovie)-[:IS_GENRE]-(genre:Genre)
RETURN outMovie.title, count(genre) AS foo
ORDER BY foo DESC
LIMIT 25
In general, you can replace RETURN with WITH if you want to extend an existing query. You just have to provide an alias for returned values that do not already have an identifier (in your case, outMovies.title would need to be aliased).
Here is a simple example with your query:
MATCH (outMovie:Movie)-[:IS_GENRE]-(:Genre)-[:IS_GENRE]-(inputMovie:Movie)
WHERE ID(inputMovie) = 0
MATCH (outMovie)-[:IS_GENRE]-(genre:Genre)
WITH outMovies.title AS title, count(genre) AS foo
ORDER BY foo DESC
LIMIT 25
RETURN COUNT(title) AS num_titles;
The returned num_titles will be at most 25.
i am using Neo4j 1.9.RC2 and i test the ORDER BY with WITH.
What i want to do is to generate a dynamic ranking and store the current sort index into each node sorted.
i have something like : parent-[r:has_child]->rank_node
I would like to do something like :
start n=node(1)
match n-[r:has_child]->rank_node
with rank_node
order by rank_node.score
set rank_node.position = "CURRENT ORDER BY INDEX"
I woul like to have a counter that increment from 0 to "n" ... I can't manage to do that ...
Here CURRENT ORDER BY INDEX is like the current index of each node return by order by.
i don't know if it is possible to do that with cyper? It would be very usefull because we can do big sorting and insert directly the position in the node to get it later directly ...
Talked to Michael Hunger and we solved it like this:
start n=node(0)
match n-[r:rank]->rank_node
with rank_node, n
match n-[r:rank]->rn
where rn.score <= rank_node.score
with rank_node,count(*) as pos
set rank_node.rank = pos
return rank_node;
For live example see: http://console.neo4j.org/?id=d07p7r
MATCH (a:person)
OPTIONAL MATCH ()-[r:knows|knowsyy]->(a)
RETURN COUNT(*) AS rank,a.mobno // //rank with two direction
person=label
know and knowsyy=relation
MATCH (n:person)-[r:knows]->(a:phonbook)
RETURN COUNT(*) AS rank,n.mobno,r.name ORDER BY n.mobno desc //rank with relation
I would like to retrieve a specific number of random nodes. The graph consists of 3 000 000 nodes where some of them are sources, some are target and some are both.
The aim is to retrieve random sources and as I don't know how to select random, the program generates k random numbers from 1 to 3 000 000 which represent node IDs and then discards all randomly selected nodes that are not sources. As this procedure is time-consuming, I wonder whether it is possible to directly select random sources with cypher query.
In case to select all sources, the query would be the following
START t=node(*) MATCH (a)-[:LEADS_TO]->(t) RETURN a
Does anyone know how would it be possible to select the limited number of random nodes directly with a cypher or, if not possible, suggest any workaround?
You can use such construction:
MATCH (a)-[:LEADS_TO]->(t)
RETURN a, rand() as r
ORDER BY r
It should return you random set of object.
Tested with Neo4j 2.1.3
You can limit your query with skip/limit so you could do
START t=node(*)
MATCH (a)-[:LEADS_TO]->(t)
RETURN a
SKIP {randomoffset} LIMIT {randomcount}
Otherwise you can also create a set of random node-id's and pass them as parameter to the cypher statement.
Another way of the one suggested here, for case you want a random Start nodes with all there connections is:
MATCH (a)-[:LEADS_TO]->[]
WITH a,rand() AS rand
ORDER BY rand LIMIT {YourLimit}
MATCH (a)-[l:LEADS_TO]->(t)
RETURN a,l,t
MATCH (n:Label)
WITH n, rand() AS r
ORDER BY r
RETURN n LIMIT <no. of random nodes>