Having a label as a parameter in a cypher query (efficiently)

Hello all,

I am looking for a way to get a label as a string from my user AND use the label optimization in my query (rather than have the engine go for a full DB scan).

2 ways I have found so far of doing so (I'll use the WITH keyword to simulate user input):
1.

WITH "facebook" as company
MATCH p = (a:company)-->(b:company)
RETURN p

This one just won't work, as cypher apparently does not know how to handle form of (node_name:label_name) when label_name is a parameter.

WITH "facebook" as company
MATCH p = (a)-->(b)
WHERE ALL (x IN nodes(p) WHERE company IN labels(x))
RETURN p

This one works, but performs a full DB scan, not using the label optimization benefit for improved performance.

Any ideas?
Thanks!

It's not clear. Do you have a node with label "facebook"?

Yep (just an example for an input string representing a label).
I'm allowing myself to assume that the given string would always represent a valid label in my graph. (side note: I don't think that really matters - if label doesn't exist in graph and query is valid, it should still run successfully and just return 0 results).

Hello @roymaor1 :slight_smile:

I had the same question earlier this week, in the doc, it says it is not possible to use parameters for labels.

Your second solution is right:

WITH "facebook" as company
MATCH p = (a)-->(b)
WHERE ALL (x IN nodes(p) WHERE company IN labels(x))
RETURN p

But @andrew_bowman advised me to use the other option:

  • write the label in the language you use to encapsulate your request, for example Python
  • to sanitize what you are appending since this is a cypher injection risk (check that the string you will use is only a label and not something else)

Example:

label = "facebook"
query = "MATCH p = (a:"+label +")-->(b:"+label +") RETURN p"

Regards,
Cobra

2 Likes

That looks good @cobra. Thanks alot

1 Like

I would add the following.

label = "facebook".Replace('`', '\'').Replace(';', '_')
query = "MATCH p = (a:`"+label +"`)-->(b:"+label +") RETURN p"

What we are doing here is we added backticks so even if the label contains illegal characters, they will be executed as string.

`label`

Then we disallow the use of the backtick and semicolon in the label. This should at least allow the script to fail if someone tries to perform injection as they cannot exit the backtick escape and cannot terminate properly resulting in a query the DB will reject.

It is not fail proof though. There will be someone who is smart that can go around this.

I know this is really late but it might help someone who lands where the same way as I did.
There is an apoc function that does this quite well:

WITH "facebook" as company
MATCH p = (a)->(b)
WHERE apoc.label.exists(a, company) AND apoc.label.exists(b, company)

This allows you to provide the label as a parameter since the apoc function accepts a string.

@Raahs

Your last cypher may work but its still going to do a AllNodesScan. If your graph has 100million nodes but only 30k nodes with label facebook your query will still examine all 100million nodes so as to find the 30k facebook nodes.
As @cobra indicated

I had the same question earlier this week, in the doc , it says it is not possible to use parameters for labels.

and this is so since the cypher planner would not now how to necessarily plan the query if a label was defined via a parameter

Very late but maybe apoc.cypher.run may help with this?

WITH "facebook" as company
CALL apoc.cypher.run("MATCH p = (a:" + company + ")-->(b:" + company + ") RETURN p", {}) YIELD value
RETURN value
1 Like
Try this:

with ["facebook"] as lbl 
MATCH p = (a)-[]-(b)
where labels(a) = labels(b) = lbl
with nodes(p)as n1, relationships(p) as rels
return n1, rels limit 22

Would not this still do an AllNodesScan?

1 Like