3
votes

I was trying to set Label and Relationship as a variable in cypher query, because I don't want to list all the label one by one and create cypher queries for all of them.

This is what I did:

class Neo4jClient(object):
    def __init__(self, uri, user, password):
        self._driver = GraphDatabase.driver(uri, auth=basic_auth(user, password))
    def close(self):
        self._driver.close()
    def merge_nodes_relationships(self, anchor_data):
        event = anchor_data.event
        anchor = anchor_data.anchor
        for k, v in anchor.items():
            relation = session.write_transaction(self.create_event_anchor_relation, event, k, v)
    @staticmethod
    def create_event_anchor_relation(tx, event, anchorkey, anchorvalue):
        result =  tx.run("MATCH(e: Event {id : $eventid}), (a: $Anchor {id:$anchorvalue)"
                         "MERGE(e)-[r:$RelationShip]-(a)"
                         "RETURN r", eventid=event['id'], Anchor=anchorkey, anchorvalue=anchorvalue, RelationShip='EVENT_' + anchorkey
                         )
        return result.single()[0]

But Error thrown saying

Invalid input '$': expected whitespace or a label name (line 1, column 10 (offset: 9))\n\"MERGE (a:$Anchor {id : $id})\"\n

So how should I fix this? if parameterized Label or Relationship is not supported, what is the best practice to handle the case when coming to many Labels with same properties but need different label name.

1

1 Answers

3
votes

This should generally be avoided, but the following will work:

MATCH (e :Event {id: $eventid}), (a {id: $anchorvalue)
WHERE $Anchor IN LABELS(a)
MERGE(e)-[r]-(a)
WHERE $RelationShip IN LABELS(r)
RETURN r

EDIT: To see why this is bad, run the following two queries:

PROFILE
MATCH (e :Event)
RETURN e

And

PROFILE
MATCH (e)
WHERE "Event" IN LABELS(e)
RETURN e

Note that they actually return the same thing, but they do it in very different ways.

The first runs a NodeByLabelScan that quickly looks up all nodes with label "Event". Because of how Neo4j is storing this data, these nodes are "stored together" and are very quick to lookup.

The second query runs AllNodesScan and then a Filter. In this way every single node in the database must be checked to see if it has "Event" as a label.

In general, if you are using the label as a variable, you haven't chosen a very good structure for your data.