Cypher - Conditional SET - neo4j

I'm trying to update a node in Neo4j, I'm passing variables to the query, and this variables could be null, and I don't want to update the node's property if the variable is null, so I tried this:
MATCH (n:address {id: $id})
SET n = {
name: COALESCE($name, n.name),
streetAddress: COALESCE($streetAddress, n.streetAddress),
build: COALESCE($build, n.build),
door: COALESCE($door, door),
latitude: COALESCE($latitude, n.latitude),
longitude: COALESCE($longitude, n.longitude)
}
RETURN (n)
But it gives the following error:
Neo4jError: Expected parameter(s): name, streetAddress, build, latitude, longitude
What can I do?

Because I'm using Javascript with the Neo4j driver for Node.js, I used string interpolation with a function to dynamically build the query:
verifyParam(param, paramName) {
if (param !== null && param !== undefined) return `SET n.${paramName} = ${param}`;
return '';
}
Then in the query string:
`
MATCH (n:address {id: $id})
${verifyParam($name, 'name')}
${verifyParam($streetAddress, 'streetAddress')}
${verifyParam($build, 'build')}
${verifyParam($door, 'door')}
${verifyParam($latitude, 'latitude')}
${verifyParam($longitude, 'longitude')}
RETURN (n)
`
Maybe is not the best solution, but I didn't found a better solution using only Cypher.

Related

Toggle relationship in Neo4J

I'm trying to implement follow/unfollow in Neo4J. I would like to write a query would toggle the relationship between two nodes.
I currently have the following query:
neoSession.writeTransaction(tx => tx.run('MATCH (me:User), (other:User) WHERE ID(me) = $me AND ID(other) = $other OPTIONAL MATCH (me)-[af:FOLLOWS]->(other) CALL apoc.do.when(af IS NULL, CREATE (me)-[f:FOLLOWS]->(other), DELETE af)', { me: req.user_id, other: req.body.user, datetime: Date.now() }));
Prettified query-only:
MATCH (me:User), (other:User)
WHERE ID(me) = $me AND ID(other) = $other
OPTIONAL MATCH (me)-[af:FOLLOWS]->(other)
CALL
apoc.do.when(
af IS NULL,
CREATE (me)-[f:FOLLOWS]->(other),
DELETE af
)
But this results in the error
Neo4jError: Invalid input '>' (line 1, column 169 (offset: 168))
"MATCH (me:User), (other:User) WHERE ID(me) = $me AND ID(other) = $other OPTIONAL MATCH (me)-[af:FOLLOWS]->(other) CALL apoc.do.when(af IS NULL, CREATE (me)-[f:FOLLOWS]->(other), DELETE af)"
The queries (last two arguments) to apoc.do.when() have to be strings, so quote each of them.
Also, in order for each of those queries to use those variables, you need to pass those variables in a parameter map as a 4th argument.
Each of the conditional queries must RETURN something, otherwise there will be no rows yielded and anything after would be a no-op.
The call must YIELD value, so that needs to be present, and last, a query cannot end with a procedure call, so you need to RETURN something.
This one should work, you can adjust it as needed:
MATCH (me:User), (other:User)
WHERE ID(me) = $me AND ID(other) = $other
OPTIONAL MATCH (me)-[af:FOLLOWS]->(other)
CALL
apoc.do.when(
af IS NULL,
"CREATE (me)-[f:FOLLOWS]->(other) RETURN f",
"DELETE af RETURN null as f",
{me:me, af:af}
) YIELD value
RETURN value.f as f

How to use parameter in neo4j cypher query

The Cypher official documentation seems to be inconsistent and misleading when it comes to assigning parameter values..we have the following examples in the refcard:
SET n.property1 = $value1
where value1 is a parameter defined
{
"value1": somevalue
}
However if you use this SET syntax you get an error value1 not defined. The correct syntax seems to be:
SET n.property1 = {value1}
also if its a MATCH query the parameter looks like this:
{
email: someemail
}
note no quotes around email
So if you have a MATCH and SET query with parameters you parameters definition looks like this:
{
email: someemail,
"status" : somestatus
}
Can someone explain this apparent inconsistency?
EDIT:
This is also an example from the neo4j docs:
using parameter with SET clause:
{
"surname" : "Taylor"
}
MATCH (n { name: 'Andres' })
SET n.surname = $surname
RETURN n
This returns surname undefined.
You can set params in neo4j desktop browser using :params.
For eg,
Execute, :params {surname: 'Taylor'}
Execute, MATCH (n { name: 'Andres' }) SET n.surname = $surname RETURN n
For more info of params, use :help params

neo4j optional match and null

Perhaps this approach is wrong but I've built a cypher query using optional matches and collect. If there is data everything is fine, if not, collect returns null for the properties specified. It looks like this is expected as per the docs.
Ideally I'd like collect to return an empty array or null when there no match is made. I'm using the following...
MATCH (p) WHERE id(p) = 11
OPTIONAL MATCH (p) -[:car]- (c)
OPTIONAL MATCH (p) -[:driver]- (u)
RETURN {
_id: id(p), name: p.name, type: p.type,
cars: collect({_id: id(c), name: c.name}),
drivers: collect({_id: id(u), name: u.email})
} AS place
Try like this
MATCH (p) WHERE id(p) = 11
OPTIONAL MATCH (p) -[:car]- (c)
OPTIONAL MATCH (p) -[:driver]- (u)
RETURN {
_id: id(p), name: p.name, type: p.type,
cars: CASE WHEN c IS NOT NULL THEN collect({_id: id(c), name: c.name}) ELSE NULL END,
drivers: CASE WHEN u IS NOT NULL THEN collect({_id: id(u), name: u.email}) ELSE NULL END
} AS place
This will check whether data is present to collect or not if present then it will return else null value will be returned

Parametrized like query in neo4j

I want to create this query as parametrized query.
var query = ["Match (name:Name)-[r:IN_CLASS]->(class:Class)-[r1:HAS_STUDENTS]->(s:Student) where id(s)=",rollno," and lower(s.Name)=~'.*",name,".*' RETURN id(s),s.Name limit 5"].join('');
I have tried this code but it is giving error :
var query = ["Match (name:Name)-[r:IN_CLASS]->(class:Class)-[r1:HAS_STUDENTS]->(s:Student) where id(s)=",rollno," and lower(s.Name)=~'.*{name}.*' RETURN id(s),s.Name limit 5"].join('');
db.query(query , {name : name} , function(err,results){
if (err) return callback(err);
if(results){
return callback(null,results);
}
else{
return callback(null,false);
}
});
Please tell me where I am wrong?
You cannot have parameters that are part of a literal. You've tried
... WHERE ... lower(s.Name)=~'.*{name}.*'
Instead the whole regex expression needs to be the parameter value:
... WHERE ... lower(s.Name)=~ {name}
You need to concatenate your value with .* to .*<value>.* on the client side and pass this in as parameter value.
Edit:
You can also concatenate in Cypher:
... WHERE ... lower(s.Name)=~'.*'+{name}+'.*'
And for case insensitive regexps use:
... WHERE ... s.Name =~'(?i).*'+{name}+'.*'

neo4jrestclient - query get id

I am using the neo4jrestclient library.
from neo4jrestclient.client import GraphDatabase
from neo4jrestclient import client
from neo4jrestclient import query
gdb = GraphDatabase("http://localhost:7474/db/data/")
q = """MATCH n RETURN n;"""
result = gdb.query(q=q)
print(result[0])
When I am executing the query "MATCH n RETURN n, the output is:
[{
'all_relationships': 'http://localhost:7474/db/data/node/1131/relationships/all',
'all_typed_relationships': 'http://localhost:7474/db/data/node/1131/relationships/all/{-list|&|types}',
'self': 'http://localhost:7474/db/data/node/1131',
'labels': 'http://localhost:7474/db/data/node/1131/labels',
'properties': 'http://localhost:7474/db/data/node/1131/properties',
'create_relationship': 'http://localhost:7474/db/data/node/1131/relationships',
'outgoing_relationships': 'http://localhost:7474/db/data/node/1131/relationships/out',
'data': {
'title': 'title',
'name': 'Poludnie'
},
'incoming_typed_relationships': 'http://localhost:7474/db/data/node/1131/relationships/in/{-list|&|types}',
'property': 'http://localhost:7474/db/data/node/1131/properties/{key}',
'paged_traverse': 'http://localhost:7474/db/data/node/1131/paged/traverse/{returnType}{?pageSize,leaseTime}',
'incoming_relationships': 'http://localhost:7474/db/data/node/1131/relationships/in',
'outgoing_typed_relationships': 'http://localhost:7474/db/data/node/1131/relationships/out/{-list|&|types}',
'traverse': 'http://localhost:7474/db/data/node/1131/traverse/{returnType}'}]
I see that the node’s id = 1131. The question is: can I obtain this id in raw forms without those links? I would like to have only the id together with the value of the ‘data’ field.
In Cypher, that could be expressed like this:
MATCH (n) RETURN {id: ID(n), name: n.name, title: n.title} as city
In the response, the data hash will contain an array and each element's row key will contain this data accessible using their given keys.
To get "just the id and data, change your query to:
MATCH (n) RETURN id(n), n.data
See if that is satisfactory.

Resources