condition in count function - neo4j

Can I put condition in count()? Let me explain.
START me=node:node_auto_index(UserProfileID = '1'), other=node(*)
MATCH pMutualFriends=me-[r?:friends]-mf-[r1:friends]-other
WHERE other.UserName? =~ '(?i)dh.*' AND other.UserProfileID? <> 1
RETURN me.EMailID, other.EMailID,other.UserProfileID, other.UserName, r.ApprovalStatus, COUNT(pMutualFriends) AS mutualCount
in above query can I user like this.
COUNT(pMutualFriends where r.ApprovalStatus = 1 AND r1.ApprovalStatus =1 )
Or may be in other way?
Thanks

The filter function should help you. If you need further assistence, please provide a data sample on http://console.neo4j.org and share it here.
As an example:
START me=node:node_auto_index(UserProfileID = '1'), other=node(*)
MATCH pMutualFriends=me-[r?:friends]-mf-[r1:friends]-other
WHERE other.UserName? =~ '(?i)dh.*' AND other.UserProfileID? <> 1
RETURN me.EMailID, other.EMailID,other.UserProfileID, other.UserName,
count(filter(x IN r.ApprovalStatus: x=1)),
count(filter(x IN r1.ApprovalStatus: x=1))

Related

apoc.cypher.mapParallel2 in Neo4j is not giving expected results

I have the following query
MATCH (e) WHERE SIZE((e:Customer)<-[:Transaction]-()) <> 0
AND SIZE(()<-[:Transaction]-(e)) <> 0
MATCH path = (e)-[:Transaction*..10]-(e) return path
I am getting the expected results with the above query.
I am trying to parallelize this query with the following query
MATCH (e:Customer) WHERE SIZE((e)<-[:Transaction]-()) <> 0 AND SIZE(()<-[:Transaction]-(e)) <> 0 WITH
collect(e.ID) AS users CALL apoc.cypher.mapParallel2("match (e:Customer)-[:Transaction*..10]->(e)
where e.ID=_ return e.ID as ll",{},users,10) yield value return value.ll
this query doesn't return anything. Kindly, please help me with this.
Does this query, which is also more efficient, work for you?
MATCH (e:Customer)
WHERE (e)<-[:Transaction]-() AND ()<-[:Transaction]-(e)
WITH collect(e) AS users
CALL apoc.cypher.mapParallel2(
"match (_)-[:Transaction*..10]->(_) return _.ID as ll",
{},users,10) YIELD value
RETURN value.ll

Compare data of two nodes of different labels in Neo4j with some property

Match(csav:CSAVHierarchy) with csav
Match(cx:CXCustomerHierarchy) with cx
Optional Match(csav)-[:CSAVCustomerHasChild]->(csa:CSAVHierarchy) where csa._type='CXCustomer' OR csa._type='CXCustomerBU'
Optional Match(cx)-[:CXCustomerHasChild]->(cxc:CXCustomerHierarchy) where cxc._type='CXCustomer' OR cxc._type='CXCustomerBU'
return
CASE
WHEN csa.ssid = cxc.ssid and csa.elementLabel = cxc.elementLabel
THEN "yes"
ELSE "No" END As result
with this query its giving cartesian issue and i want to carry forward both the nodes data for further use.
where I m lacking?
You can use the Apoc plugin (see https://neo4j-contrib.github.io/neo4j-apoc-procedures):
Match(n:Person{ssid:"1234"}) with collect(n) as nodes CALL apoc.refactor.mergeNodes(nodes) YIELD node RETURN node
This query may do what you want. It returns the unique cxc and csa pairs that pass all your tests.
MATCH (csa:CSAVHierarchy)
WHERE
(:CSAVHierarchy)-[:CSAVCustomerHasChild]->(csa) AND
csa._type='CXCustomer' OR csa._type='CXCustomerBU'
MATCH (cxc:CXCustomerHierarchy)
WHERE
(:CXCustomerHierarchy)-[:CXCustomerHasChild]->(cxc) AND
csa.ssid = cxc.ssid AND
csa.elementLabel = cxc.elementLabel AND
(cxc._type='CXCustomer' OR cxc._type='CXCustomerBU')
RETURN cxc, csa
For better performance, you should also create indexes on :CSAVHierarchy(_type) and :CXCustomerHierarchy(_type).
This the solution I came up with
MATCH(cxc:CXCustomerHierarchy)-[:_properties]->(auditnode)-->(spoke)
where cxc._type='CXCustomer' OR cxc._type='CXCustomerBU' AND spoke.start_date <= 1554272198875 <= spoke.end_date AND spoke.status = "Confirmed"
with cxc
OPTIONAL MATCH (cxc)<-[r:CXCustomerHasChild]-(parent) with cxc
MATCH(csav:CSAVHierarchy)-[:_properties]->(auditnode)-->(spoke) with cxc,csav
where csav._type='CXCustomer' OR csav._type='CXCustomerBU' AND spoke.start_date <= 1554272198875 <= spoke.end_date AND spoke.status = "Confirmed"
OPTIONAL MATCH (csav)<-[r:CSAVCustomerHasChild]-(parent) with csav,cxc
return
CASE
WHEN csav.sourceSystemId <> cxc.sourceSystemId , csav.elementLabel <> cxc.elementLabel
THEN csav.elementLabel
ELSE "SIMILAR DATA " END As result

How to execute cypher query within a CASE WHEN THEN clause in Neo4j Cypher

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;

Get count of multiple nodes with no relations in cypher query

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

neo4j cypher left padding String in Where Clause

I have a String property in my nodes where the length of the String isn't fix.
Now i must search the right node by this property but i get a fixed length value from another System. For Example my Node has the Value '0123' but I get the Information '000123' for searching.
I need a function like left padding with Zeros and this in the Where Clause like
MATCH (a:LABEL) where leftPad(a.property, 6, '0') = '000123' return a
LIMIT 1
Is something like this possible with a good Performance?
You could do this:
MATCH (a:LABEL)
WHERE SUBSTRING('00000', 0, SIZE(a.property)) + a.property = '000123'
RETURN a
LIMIT 1;
Or, if all the characters are numeric, then you could do this:
MATCH (a:LABEL)
WHERE TOINT(a.property) = TOINT('000123')
RETURN a
LIMIT 1;
However, it would be even better if you could just store the property value as an integer in the first place, and also compare it to an integer, which would be the fastest. This might be very easy to do, depending on your situation.
MATCH (a:LABEL)
WHERE a.property = 000123
RETURN a
LIMIT 1;
Try it with reduce:
MATCH (a:LABEL)
WHERE REDUCE(lp='', n in RANGE(0,5-size(a.name)) | lp+'0')+a. a.property = '000123'
RETURN a
or try it with regular expression:
MATCH (a:LABEL)
WHERE a.property =~ '(0){0,3}123'
RETURN a

Resources