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.
Related
I have the following query:
MATCH (u:User)
WHERE u.id = $userId
MERGE (p:Palette {name: $name})
ON CREATE
SET p.name = $name
SET p.id = apoc.create.uuid()
MERGE (u)-[cr:CREATED]->(p)
MERGE (u)-[sa:SAVED]->(p)
WITH p MATCH (p)-[in:INCLUDES]->()
DELETE in
WITH u MATCH (p:Palette)
WHERE (u)-[:SAVED]-() AND p.name = $name
FOREACH (color IN $colors |
MERGE (c:Color {hex: color.hex})
ON CREATE
SET c.hex = color.hex
MERGE (p)-[inc:INCLUDES]->(c)
Everything works as expected up to DELETE in and then nothing else happens. I get the following error:
Neo4jError: Invalid input '': expected
")"
"CALL"
"CREATE"
"DELETE"
"DETACH"
"FOREACH"
"LOAD"
"MATCH"
"MERGE"
"ON"
"OPTIONAL"
"REMOVE"
"RETURN"
"SET"
"UNWIND"
"USE"
"WITH"
How can I continue this query after the DELETE statement? If I separate this into 2 queries (the first one ending at DELETE in), then everything works as expected.
If I understand correctly, the p before the DELETE is the same as the p after it. Id this is the case, use WITH to keep the items you already searched for. So you can try:
MATCH (u:User)
WHERE u.id = $userId
MERGE (p:Palette {name: $name})
ON CREATE
SET p.name = $name
SET p.id = apoc.create.uuid()
MERGE (u)-[cr:CREATED]->(p)
MERGE (u)-[sa:SAVED]->(p)
WITH p, u MATCH (p)-[inc:INCLUDES]->()
WITH p, u, inc
DELETE inc
WITH p
FOREACH (color IN $colors |
MERGE (c:Color {hex: color.hex})
ON CREATE
SET c.hex = color.hex
MERGE (p)-[inc:INCLUDES]->(c)
I tried:
MATCH (p:Palette)
WHERE p.name = "First test palette"
MATCH (p)-[inc:INCLUDES]->(c:Color)
WITH p, inc
DELETE inc
WITH p
MATCH (u)-[:SAVED]-(p)
RETURN u, p
On this data sample:
MERGE (e:User {name: "user"})
MERGE (a:Palette {name: "First test palette"})
MERGE (b:Color {hex: "#123123"})
MERGE (c:Color {hex: "#ffffff"})
MERGE (d:Color {hex: "#000000"})
MERGE (a)-[:INCLUDES]-(b)
MERGE (a)-[:INCLUDES]-(c)
MERGE (a)-[:INCLUDES]-(d)
MERGE (e)-[:SAVED]-(a)
And it worked as expected.
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;
I have two users:
CREATE (a:user {id: 1})
CREATE (b:user {id: 2})
I want users to be able to follow each other:
MATCH (a:user {id: 1}), (b:user {id: 2})
CREATE (a)-[r:FOLLOWS]->(b)
But I also need to keep track of when that follow happened:
MATCH (a:user {id: 1}), (b:user {id: 2})
CREATE (a)-[r:FOLLOWS {t: 32409823}]->(b)
My issue is that I need create the :FOLLOWS relation if it does not already exist without making a query to check, then another query to create it. Ideally CREATE UNIQUE would solve this, which works just fine without any changing fields on the relation:
MATCH (a:user {id: 1}), (b:user {id: 2})
CREATE UNIQUE (a)-[r:FOLLOWS]->(b)
(THIS WORKS)
But when I include a timestamp on the relation, create unique will make a second relation because it has a different timestamp.
MATCH (a:user {id: 1}), (b:user {id: 2})
CREATE UNIQUE (a)-[r:FOLLOWS {t: 32409823}]->(b)
(THIS DOESN'T WORK)
The above creates a new relation every time because the timestamp is always changing. Is there any way I can check if any relation with the label :FOLLOWS exists and create the relation with fields if it doesn't?
MERGE and its ON CREATE clause should do what you want. MERGE will match on the :FOLLOWS relationship, and if it does not exist it will create it. ON CREATE is only performed if the MERGE operation created the relationship instead of matching on an existing one.
MATCH (a:user {id: 1}), (b:user {id: 2})
MERGE (a)-[r:FOLLOWS]->(b)
ON CREATE SET r.t = timestamp()
I have the below data set on neo4j
create (recipe1:recipe {name: 'recipe-1'})
create (recipe2:recipe {name: 'recipe-2'})
create (recipe3:recipe {name: 'recipe-3'})
create (recipe4:recipe {name: 'recipe-4'})
create (recipe5:recipe {name: 'recipe-5'})
create (recipe6:recipe {name: 'recipe-6'})
create (user1:user {name: 'user-1'})
create (user2:user {name: 'user-2'})
create (user3:user {name: 'user-3'})
create (user4:user {name: 'user-4'})
create
(user1)-[:LIKES]->(recipe1),
(user1)-[:LIKES]->(recipe2),
(user1)-[:LIKES]->(recipe4),
(user2)-[:LIKES]->(recipe4),
(user2)-[:LIKES]->(recipe6),
(user3)-[:LIKES]->(recipe1),
(user3)-[:LIKES]->(recipe3),
(user3)-[:LIKES]->(recipe6),
(user4)-[:LIKES]->(recipe4)
and trying to run the below query:
match (user4:user {name: 'user-4'})-[LIKES]->recipe<-[:LIKES]-slm-[:LIKES]->recommendations
where not(user4 = slm) and not(user4-recommendations)
return count(*) AS recommendationsWeight,
recommendations.name AS name
order by recommendationsWeight DESC, name DESC
but I am getting the below error:
Type mismatch: expected Float or Integer but was Node (line 2, column 32 (offset: 123))
"where not(user4 = slm) and not(user4-recommendations)"
^
any idea what I am doing wrong here?
Update:
What I want to do here with not(user4-recommendations) is to say that any recommendations which user4 has no relationship with. For example, consider this:
match (user4:user {name: 'user-4'}), (recipe1:recipe {name: 'recipe-1'})
create (user4)-[:DISLIKES]->(recipe1)
So, the result of my recommendation query should not include recipe1 as user has interacted with it before.
You have a typo:: - instead =. And do not forget the parentheses:
match (user4:user {name: 'user-4'})-[LIKES]->
(recipe)
<-[:LIKES]-(slm)-[:LIKES]->
(recommendations)
where not(user4 = slm) and not(user4 = recommendations)
return count(*) AS recommendationsWeight,
recommendations.name AS name
order by recommendationsWeight DESC,
name DESC
I think that you're trying to build a recommendatory system. Then, the request will be easier (no checks are not necessary, it works because it is not used a zero-length path):
match (user4:user {name: 'user-4'})
-[:LIKES]->(recipe)<-[:LIKES]-
(slm)-[:LIKES]->(recommendations)
where not ( (user4)-[:DISLIKES|LIKES]->(recommendations) )
return recommendations,
count(recommendations) as recommendationsWeight
order by recommendationsWeight desc,
recommendations.name asc
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)