neo4j pass parameter to variable length relationship - neo4j

How do I use parameters with variable length relationships?
MATCH path=(:Person {id: {id}})=[:HAS_FRIEND*0..{num_friends}]->(:Person)
I'm trying to create a generic query so that I can pass a value 'num_friends' into the cypher query for various levels of relationships that I need.
I get an error so I'm wondering how something like this would be done?

Parameters can not be used as hops count.
But you can use path expander from apoc:
match (P:Person {id: {id}}) with P
call apoc.path.expand( P, 'HAS_FRIEND>', 'Person', 0, {num_friends}) yield path
return path
Adapted for comment:
match (P:Person {id: {id}}) with P
call apoc.path.expand( P, 'HAS_FRIEND>', 'Person', 0, {num_friends}) yield path
with path, last(nodes(path)) as lst where not (lst)-[:HAS_FRIEND]->(:Person)
return path

Related

query with both MATCH and CREATE

I have 3 Nodes:
:User which has a unique id property
:Palette which has a unique name property
:Color which has a unique hex property
When a user saves a pallete I would like to:
create a new pallete if a palette with this name does not exist, and add a :CREATED relationship from the :User to the :Palette
create a :SAVED relationship from the :User to the :Palette if one does not exist
Afterwards I would like to delete all :INCLUDES relationships that this :Palette has to :Color nodes inside the database (in order to create new ones afterwards).
This is my query (I replaced the variables with hardcoded strings so it's easier to execute):
MATCH (u:User)
WHERE u.id = '4f3d1904'
MERGE (p:Palette {name: 'Test'})
ON CREATE
SET p.name = "Test"
MERGE (u)-[cr:CREATED]->(p)
MERGE (u)-[sa:SAVED]->(p)
MATCH (p:Palette {name: 'Test'})-[in:INCLUDES]->()
DELETE in
When running the query I get the following error:
WITH is required between MERGE and MATCH (line 8, column 1 (offset: 181))
"MATCH (p:Palette {name: 'Test'})-[in:INCLUDES]->()"
^
But if I add a WITH I get the following:
MATCH (u:User)
WHERE u.id = '4f3d1904'
MERGE (p:Palette {name: 'Test'})
ON CREATE
SET p.name = "Test"
MERGE (u)-[cr:CREATED]->(p)
MERGE (u)-[sa:SAVED]->(p)
WITH
MATCH (p:Palette {name: 'Test'})-[in:INCLUDES]->()
DELETE in
Invalid input ')': expected whitespace or a relationship pattern (line 9, column 32 (offset: 217))
"MATCH (p:Palette {name: 'Test'})-[in:INCLUDES]->()"
^
What am I doing wrong?
MERGE and MATCH stages (or MATCH and MATCH) require a WITH between them in order to use the result of the former in the latter.
In your case you can use the p that you already have like this:
...
WITH p
MATCH (p)-[in:INCLUDES]->()
DELETE in
So you won't need to find it again. without the WITH, it is like two different queries.

(Neo4j, Cypher) How to set incremental number to relationships?

i'm using neo4j. what i'd like to do is to create a root node for search result and to create relationships from root node to search result nodes. and I'd like to set incremental number to each relationship's property.
if possible, with one query.
Sorry for not explaining enough.
This is what I'd like to do.
Any more concise way?
// create test data
WITH RANGE(0, 99) AS indexes,
['Paul', 'Bley', 'Bill', 'Evans', 'Robert', 'Glasper', 'Chihiro', 'Yamanaka', 'Fred', 'Hersch'] AS names
UNWIND indexes AS index
CREATE (p:Person { index: index, name: (names[index%10] + toString(index)) });
// create 'Results' node with relationships to search result 'Person' nodes.
// 'SEARCH_RESULT' relationships have 'order' and 'orderBy' properties.
CREATE(x:Results{ts: TIMESTAMP()})
WITH x
MATCH(p:Person)
WHERE p.name contains '1'
MERGE(x)-[r:SEARCH_RESULT]->(p)
WITH x, r, p
MATCH (x)-[r]->(p)
WITH x, r, p
ORDER BY p.name desc
WITH RANGE(0, COUNT(r)-1) AS indexes, COLLECT(r) AS rels
UNWIND indexes AS i
SET (rels[i]).order = i
SET (rels[i]).orderBy = 'name'
RETURN rels;
// validate
MATCH(x:Results)-[r:SEARCH_RESULT]->(p:Person)
RETURN r, p.name ORDER BY r.order;

Optional nodes in a path?

I'm trying to write a query where I get the :LIKES relationships.
(:USER)
|
[:CREATED]
|
(:POST)<-[:LIKES]-(:USER)
|
[:RESHARED]
|
(:POST)<-[:LIKES]-(:USER)
I was trying something along the lines of:
MATCH (u:USER {name: "Lamoni"})-[:CREATED]-(p:POST)
OPTIONAL MATCH p<-[:LIKES]-(u2:USER)
OPTIONAL MATCH p<-[:RESHARED]-(p2:POST)<-[:LIKES]-(u3:USER)
Any ideas on an optimal way to do this and be able to order them by a property called created_at in a descending order?
Thanks!
If the POST structure always looks like this you can try:
// match the whole user-post-post path
MATCH (u:USER {name: "Lamoni"})-[:CREATED]-(p_direct:POST)-[:RESHARED]-(p_shared:Post)
WITH u, p_direct, p_shared
OPTIONAL MATCH (p_direct)<-[:LIKES]-(u2:USER)
OPTIONAL MATCH (p_shared)<-[:LIKES]-(u3:USER)
RETURN u.name, p_direct.xyz, collect(u2.name), p_shared.xyz, collect(u3.name)
If you just want all USERS that like a POST by a given USER (independent of the type of POST, created or shared) you can also collect all POST:
MATCH (u:USER {name: "Lamoni"})-[:CREATED|RESHARED*1..2]-(p:Post)
WITH u, p
OPTIONAL MATCH (p)<-[:LIKES]-(u2:USER)
WITH u.name, p, u2
ORDER BY u2.created_at
RETURN u.name, p, collect(u2.name)

Return one result per person in neo4j

Assuming I have this graph in neo4j:
CREATE (a:Person {name: "Person A"})
CREATE (b:Person {name: "Person B"})
CREATE (r1:TestA {result: 1})
CREATE (r2:TestA {result: 2})
CREATE (r3:TestA {result: 3})
CREATE (r4:TestA {result: 3})
CREATE (a)-[:RESULT]->(r1)
CREATE (a)-[:RESULT]->(r2)
CREATE (b)-[:RESULT]->(r3)
CREATE (b)-[:RESULT]->(r4);`
How would I return only the best (being the Result with the lowest result property) result for each person?
If I do
`MATCH (p:Person)-->(t:TestA) RETURN p, t ORDER BY t.result LIMIT 1;`
I only get (a)-->(r1), as expected, but I want to get (a)-->(r1) AND (b)-->(r3 or r4).
Any hints on how to achieve this? Thanks in advance.
You can use a aggregation function in cypher:
MATCH (p:Person)-[:RESULT]->(t) RETURN p, min(t.result)
However this will not return a row for person not having a RESULT relationship. Using OPTIONAL MATCH can help with this.

match in clause in cypher

How can I do an match in clause in cypher
e.g. I'd like to find movies with ids 1, 2, or 3.
match (m:movie {movie_id:("1","2","3")}) return m
if you were going against an auto index the syntax was
START n=node:node_auto_index('movie_id:("123", "456", "789")')
how is this different against a match clause
The idea is that you can do:
MATCH (m:movie)
WHERE m.movie_id in ["1", "2", "3"]
However, this will not use the index as of 2.0.1. This is a missing feature in the new label indexes that I hope will be resolved soon. https://github.com/neo4j/neo4j/issues/861
I've found a (somewhat ugly) temporary workaround for this.
The following query doesn't make use of an index on Person(name):
match (p:Person)... where p.name in ['JOHN', 'BOB'] return ...;
So one option is to repeat the entire query n times:
match (p:Person)... where p.name = 'JOHN' return ...
union
match (p:Person)... where p.name = 'BOB' return ...
If this is undesirable then another option is to repeat just a small query for the id n times:
match (p:Person) where p.name ='JOHN' return id(p)
union
match (p:Person) where p.name ='BOB' return id(p);
and then perform a second query using the results of the first:
match (p:Person)... where id(p) in [8,16,75,7] return ...;
Is there a way to combine these into a single query? Can a union be nested inside another query?

Resources