How to use parameter in neo4j cypher query - neo4j

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

Related

Cypher - Conditional SET

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.

Query to find all shortest path with additional condition returns no records

I have to find all shortest paths between A and B with additional property.
This query returns me only one route (and this is true, there is only one route which has 3 parts):
MATCH (darjeeling { name: 'Darjeeling' }),(sandakphu { name: 'Sandakphu' }),
paths = allShortestPaths((darjeeling)-[*]-(sandakphu))
RETURN paths
Results:
{"start":{"identity":1,"labels":["town"],"properties":{"name":"Darjeeling"}},"end":{"identity":3,"labels":["peak"],"properties":{"altitude":"12400 ft","name":"Sandakphu"}},"segments":[{"start":{"identity":1,"labels":["town"],"properties":{"name":"Darjeeling"}},"relationship":{"identity":2,"start":1,"end":0,"type":"trek","properties":{"distance":15,"name":"Darjeeling-Rimbik","winter":"true","summer":"true"}},"end":{"identity":0,"labels":["town"],"properties":{"name":"Rimbik"}}},{"start":{"identity":0,"labels":["town"],"properties":{"name":"Rimbik"}},"relationship":{"identity":3,"start":0,"end":2,"type":"trek","properties":{"distance":18,"name":"Rimbik-BhikeBhanja","winter":"true","summer":"true"}},"end":{"identity":2,"labels":["village"],"properties":{"name":"BhikeBhanja"}}},{"start":{"identity":2,"labels":["village"],"properties":{"name":"BhikeBhanja"}},"relationship":{"identity":4,"start":2,"end":3,"type":"trek","properties":{"distance":4,"name":"BhikeBhanja-Sandakphu","winter":"true","summer":"true"}},"end":{"identity":3,"labels":["peak"],"properties":{"altitude":"12400 ft","name":"Sandakphu"}}}],"length":3}
All parts of this route has property winter set to true, but if I want to add such a condition to my query, I have no results:
MATCH (darjeeling { name: 'Darjeeling' }),(sandakphu { name: 'Sandakphu' }),
paths = allShortestPaths((darjeeling)-[*]-(sandakphu))
WHERE ALL (p IN relationships(paths) WHERE p.winter = true)
RETURN paths
My question is, why the second query retuns no results even though there is a route between A and B, this is the shortest route at all, and all paths on this route has property winter set to true?
Formalizing this into an answer.
Looks like you've got string properties instead of boolean properties. This condition should work for you:
WHERE p.winter = "true"
If you want to change these into boolean properties, you'll need to match on all relationships with this property and use:
SET p.winter = (p.winter = "true")
I believe you need do another MATCH for the paths, like this:
MATCH (darjeeling { name: 'Darjeeling' }), (sandakphu { name: 'Sandakphu' })
MATCH paths = allShortestPaths((darjeeling)-[*]-(sandakphu))
WHERE ALL (p IN relationships(paths) WHERE p.winter = true)
RETURN paths

Grails Criteria dynamic AND conditions for one-to-many relationship

I have a domain class
class Url {
UUID id
String url
static hasMany = [
indications:UrlIndication
]
...
}
And
class UrlIndication {
UUID id
String name
static belongsTo = Url
...
}
I want to choose urls so that it has all the necessary UrlIndication elements in a given list indicationsId.
For that I use an association and criteria like this one:
indications {
and {
indicationsId.each{
indication->
eq ('id',UUID.fromString(indication as String))
}
}
}
However, all I got is an empty result. Can you suggest any modifications/ other methods so that I can do this? Thanks in advance
Your query returned an empty list because it's the equivalent of the expression (pseudo-code): if 1 = 1 and 1 = 2 and 1 = 3
Such an expression would always be false. in or inList would not work for the reason #innovatism described.
In theory, Criteria's eqAll() or HQL's = ALL would work. But, I don't know for sure because I could not get either one to work.
What will work is to use inList to return a subset of Urls: those which contain at least one of the UrlIndication IDs. Then use Groovy's containsAll() to finish the job.
def ids = indicationsId.collect { UUID.fromString(it as String) }
Url.createCriteria()
.buildCriteria {
indications {
inList 'id', ids
}
}
.setResultTransformer(org.hibernate.Criteria.DISTINCT_ROOT_ENTITY)
.list()
.findAll {
it.indications.id.containsAll(ids)
}
Since the query has the potential to return duplicate Url instances, the ResultTransformer is set to return a unique list.
Finally, findAll() is used along with containsAll() to filter the list further.
Using eqAll (maybe)
Something like the following might work. Something funky is going on with Grails' HibernateCriteriaBuilder that causes the eqAll method to look up properties in the root entity; completely ignoring the sub criteria. So the following uses Hibernate directly. It didn't work for me, but it's as close as I could get. And it gave me a head-ache!
Url.createCriteria().buildCriteria {}
.createCriteria('indications', 'i')
.add(org.hibernate.criterion.Property.forName('i.id').eqAll(org.hibernate.criterion.DetachedCriteria.forClass(UrlIndication)
.add(org.hibernate.criterion.Restrictions.in('id', ids))
.setProjection(org.hibernate.criterion.Property.forName('id'))
))
.setResultTransformer(org.hibernate.Criteria.DISTINCT_ROOT_ENTITY)
.list()
The problem I had is I could not get Restrictions.in to work. Restrictions.eq works fine.
the in clause should do:
indications {
'in' 'id', indicationsId.collect{ UUID.fromString indication.toString() }
}

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}+'.*'

Neo4j and json creating multiple nodes with multiple params

I tried many things but of no use.
I have already raised a question on stackoverflow earlier but I am still facing the same issue.
Here is the link to old stackoverflow question
creating multiple nodes with properties in json in neo4j
Let me try out explaining with a small example
This is the query I want to execute
{
"params" : {
"props" : [
{
"LocalAsNumber" : 0,
"NodeDescription" : "10TiMOS-B-4.0.R2 ",
"NodeId" : "10.227.28.95",
"NodeName" : "BLR_WAO_SARF7"
}
]
},
"query" : "MATCH (n:Router) where n.NodeId = {props}.NodeId RETURN n"}
For simplicity I have added only 1 props array otherwise there are around 5000 props. Now I want to execute the query above but it fails.
I tried using (props.NodeId}, {props[NodeID]} but everything fails.
Is it possbile to access a individual property in neo4j?
My prog is in c++ and I am using jsoncpp and curl to fire my queries.
If you do {props}.nodeId in the query then the props parameter must be a map, but you pass in an array. Do
"props" : {
"LocalAsNumber" : 0,
"NodeDescription" : "10TiMOS-B-4.0.R2 ",
"NodeId" : "10.227.28.95",
"NodeName" : "BLR_WAO_SARF7"
}
You can use an array of maps for parameter either with a simple CREATE statement.
CREATE ({props})
or if you loop through the array to access the individual maps
FOREACH (prop IN {props} |
MERGE (i:Interface {nodeId:prop.nodeId})
ON CREATE SET i = prop
)
Does this query string work for you?
"MATCH (n:Router) RETURN [p IN {props} WHERE n.NodeId = p.NodeId | n];"

Resources