Is it right to use subquery inside CASE ?
MATCH (p:Person)
SET p.total =
CASE
WHEN HAS (p.total)
THEN p.total
ELSE
MATCH (p)-[:CHILD]->(c)
RETURN sum(c.age)
END
RETURN DISTINCT p
I get the following error when I try to do this.
Invalid input ']': expected an identifier character, whitespace, NodeLabel, a property map or a relationship pattern
" MATCH (p)-[:CHILD]->(c)"
You can do it but there will be better ways in the future:
MATCH (p:Person)
SET p.total =
CASE WHEN HAS (p.total)
THEN p.total
ELSE reduce(sum = 0, path in (p)-[:CHILD]->() | sum + (nodes(path)[1]).age)
END
RETURN DISTINCT p
or actually:
MATCH (p:Person)
SET p.total =
COALSECE(p.total,
reduce(sum = 0, path in (p)-[:CHILD]->() | sum + (nodes(path)[1]).age)
)
RETURN DISTINCT p
Related
I have the following params in my Neo4J:
{
"lists": [
{
"from": "someone",
"to": "somebody"
}
]
}
And the following query:
MATCH (c:Concept{name:'infranodus'}) WITH c, $lists AS list
UNWIND CASE WHEN list = [{}] THEN [null] ELSE list END AS l
WITH l
MATCH (cp1:Concept{name:l.from})
WITH cp1
MATCH (cp2:Concept{name:'somebody'})
RETURN cp1,cp2;
The query above will work.
However, if I replace l.from with a non-existent parameter, e.g. l.about, then — as the match doesn't happen — the second cp2 match doesn't fire.
How can I change this behavior and continue executing this query even if cp1 is not found? Maybe there's a way to pass on a dummy variable as a result?
MATCH (c:Concept{name:'infranodus'}) WITH c, $lists AS list
UNWIND CASE WHEN list = [{}] THEN [null] ELSE list END AS l
WITH l
MATCH (cp1:Concept{name:l.about})
WITH cp1
MATCH (cp2:Concept{name:'somebody'})
RETURN cp1,cp2;
Use OPTIONAL MATCH. If there is no match is found, then it will use NULL for the missing part of the pattern. It is similar to outer join in SQL.
NEW:
OPTIONAL MATCH (cp1:Concept{name:l.about})
OLD:
MATCH (cp1:Concept{name:l.about})
You can maybe replace it with an IN predicate ?
For eg :
WITH {from: 'Matt Olg', about: 'Matthew Olg'}
AS l
MATCH (n:Person)
WHERE n.name IN [l.from, l.to]
RETURN n.name
╒══════════╕
│"n.name" │
╞══════════╡
│"Matt Olg"│
└──────────┘
I have a use case where I am trying to optimize my Neo4j db calls and code by using the RETURN CASE WHEN THEN clauses in Cypher to run different queries depending on the WHEN result. This is my example:
MATCH (n {email: 'abc123#abc.com'})
RETURN
CASE WHEN n.category='Owner' THEN MATCH '(n)-[r:OWNS]->(m)'
WHEN n.category='Dealer' THEN MATCH (n)-[r:SUPPLY_PARTS_FOR]->(m)
WHEN n.category='Mechanic' THEN MATCH (n)-[r:SERVICE]-(m) END
AS result;
I am not sure this is legal but this is what I want to achieve. I am getting syntax errors like Invalid input '>'. How can I achieve this in the best manner?
EDIT for possible APOC solution:
This was my plan before discovering the limitation of FOREACH...
MATCH (user:Person {email:{paramEmail}})
FOREACH (_ IN case when 'Owner' = {paramCategory} then [1] else [] end|
SET user:Owner, user += queryObj
WITH user, {paramVehicles} AS coll
UNWIND coll AS vehicle
MATCH(v:Vehicles {name:vehicle})
CREATE UNIQUE (user)-[r:OWNS {since: timestamp()}]->(v)
SET r += paramVehicleProps
)
FOREACH (_ IN case when 'Mechanic' = {Category} then [1] else [] end|
SET user:Owner, user += queryObj
WITH user, {paramVehicles} AS coll
….
)
FOREACH (_ IN case when 'Dealer' = {paramCategory} then [1] else [] end|
SET user:Owner, user += queryObj
WITH user, {paramVehicles} AS coll
…...
)
RETURN user,
CASE {paramCategory}
WHEN 'Owner' THEN [(n)-[r:OWNS]->(m) | m and r]
WHEN 'Dealer' THEN [(n)-[r:SUPPLY_PARTS_FOR]->(m) | m]
WHEN 'Mechanic' THEN [(n)-[r:SERVICE]-(m) | m]
END AS result`,{
paramQueryObj: queryObj,
paramVehicles: makeVehicleArray,
paramVehicleProps: vehiclePropsArray,
paramSalesAgent: dealerSalesAgentObjarray,
paramWarehouseAgent: dealerWarehouseAgentObjarray
}).....
does anyone know to convert this using apoc.do.when()? note I need 'm' and 'r' in the first THEN.
You should still use a label in your first match, otherwise you get a full database scan and not a index lookup by email!!
for your query you can use pattern comprehensions:
MATCH (n:Person {email: 'abc123#abc.com'})
RETURN
CASE n.category
WHEN 'Owner' THEN [(n)-[r:OWNS]->(m) | m]
WHEN 'Dealer' THEN [(n)-[r:SUPPLY_PARTS_FOR]->(m) | m]
WHEN 'Mechanic' THEN [(n)-[r:SERVICE]-(m) | m] END
AS result;
It is also possible to use apoc.do.case: https://neo4j.com/labs/apoc/4.4/overview/apoc.do/apoc.do.case/
CALL apoc.do.case([
false,
'CREATE (a:Node{name:"A"}) RETURN a AS node',
true,
'CREATE (b:Node{name:"B"}) RETURN b AS node'
],
'CREATE (c:Node{name:"C"}) RETURN c AS node',{})
YIELD value
RETURN value.node AS node;
I'm struggling with problem of creating query in Cypher.
Let's use this graph as an example:
MERGE(a:Person {name:'Alice', age:38, eyes:'brown'})
MERGE(c:Person {name:'Charlie', age:53, eyes:'green'})
MERGE(d:Person {name:'Daniel', age:54, eyes:'brown'})
MERGE(b:Person {name:'Bob', age:25, eyes:'blue'})
MERGE(a)-[:KNOWS]->(c)
MERGE(a)-[:KNOWS]->(b)
MERGE(c)-[:KNOWS]->(d)
MERGE(b)-[:KNOWS]->(d)
I would like to have query that returns me nodes with name = 'Alice' only if there aren't any nodes with name = 'Bob'. So if there is Bob I would like to see no results.
Here is what I've tried:
1) With exists()
MATCH p =(n)-[*1..3]->(b)
WHERE n.name = 'Alice' AND NOT EXISTS ((n {name: 'Bob'})-[*1..3]->(b))
RETURN p
But it returns all nodes and relationships.
2) With none()
MATCH p =(n)-[*1..3]->(b)
WHERE n.name = 'Alice' AND NONE (x IN nodes(p) WHERE x.name = 'Bob')
RETURN p
This returned all nodes, without Bob...
3) with any()
MATCH p =(n)-[*1..3]->(b)
WHERE n.name = 'Alice' AND NOT ANY (x IN nodes(p) WHERE x.name = 'Bob')
RETURN p
But this gave me the same result as above.
I'm running out of ideas how to return Alice only if Bob is not present.
What I would expect from query is to return Alice when I delete Bob, but when such node exists - nothing.
Any help is appreciated:)
Thanks!
You should try this query :
MATCH (n:Person {name:'Alice'})
WHERE NOT (n)-[:KNOWS*..3]-(:Person {name:'Bob'})
RETURN n
How to get the count of more than one nodes.
MATCH (n1:node1)
MATCH (n2:node2)
MATCH (n3:node3) where n3.status = "active"
return count(n1) as countOfNode1,
count(n2) as countOfNode2,
count(n3) as countOfNode3
This query is returning duplicated result as
countOfNode1 = 0
countOfNode2 = 0
countOfNode3 = 0
where the real count is
countOfNode1 = 0
countOfNode2 = 3
countOfNode3 = 1
How to do this?
Using 'distinct' also does not solve the problem.
Given as:
return count(distinct n1) as countOfNode1,
count(distinct n2) as countOfNode2,
count(distinct n3) as countOfNode3
One possibility I'm thinking of is this
MATCH (n1:node1) WITH count(n1) as countOfNode1
MATCH (n2:node2) WITH count(n2) as countOfNode2
MATCH (n3:node3) where n3.status = "active" WITH count(n3) as countOfNode3
return countOfNode1,
countOfNode2,
countOfNode3
Or maybe
MATCH (n1:node1), (n2:node2),(n3:node3 {status:"active"} )
return count(n1) as countOfNode1,
count(n2) as countOfNode2,
count(n3) as countOfNode3
I would like to return for a given node-id related nodes and their relationships props
For example:
-> defines a bi direction relationship with property timestamp
1234->777
777->1234
1234->999
999->1234
1234->888
888->1234
1234,777,888,999 are node-ids
When I execute this:
final PreparedStatement ps = conn.prepareStatement("start a = node(1234) match (a)-[k:nearby*]->(b) where a<>b return DISTINCT b, k");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map result = (Map<String, Object>) rs.getObject("b");
System.out.println(result.toString());
}
} catch (SQLException e) {
e.printStackTrace();
logger.error("Error returning userId=" + userIdInput, e);
}
return null;
}
I get:
{userId=777}
{userId=999}
{userId=888}
{userId=888}
{userId=999}
{userId=999}
{userId=777}
{userId=888}
{userId=888}
{userId=777}
{userId=888}
{userId=777}
{userId=999}
{userId=999}
{userId=777}
How I do get distinct results only (777,888,999)
How to retrieve the relationship props of 1234 to the dest node? I expect to get the timestamp prop which defined on each relationship
Thank you,
ray.
I'm not sure what language you're using so I'll focus on the Cypher. Firstly I would replace the START query with a MATCH with a WHERE on ID(a):
MATCH (a)-[k:nearby*]->(b)
WHERE ID(a) = 1234 AND a<>b
RETURN DISTINCT b, k
Secondly I'm pretty sure you don't need the a<>b because Cypher paths won't loop back on the same nodes:
MATCH (a)-[k:nearby*]->(b)
WHERE ID(a) = 1234
RETURN DISTINCT b, k
Lastly, and to your question, I suspect the reason that you're getting duplicates is because you have multiple relationships. If so you can return the result node and an array of the relationships like so:
MATCH (a)-[k:nearby*]->(b)
WHERE ID(a) = 1234
RETURN collect(b), k
That should return you node/relationship objects (with properties on both). Depending on your language/library you might get Maps or you might get objects wrapping the data
If your library doesn't return the start/end nodes for relationships for you, you can do something like this:
MATCH (a)-[k:nearby*]->(b)
WHERE ID(a) = 1234
RETURN collect({rel: b, startnode: startnode(b), endnode: endnode(b)}), k
Hopefully that helps!
You get non distinct results, because you return both b and k
If you only want to get distinct b's use:
MATCH (a)-[k:nearby*]->(b)
WHERE ID(a) = 1234 AND a<>b
RETURN DISTINCT b
You should also use parameters!
MATCH (a)-[k:nearby*]->(b)
WHERE ID(a) = {1} AND a<>b
RETURN DISTINCT b
ps.setInt(1,1234);