Search code examples
neo4jpy2neo

Creating relationship queries in py2neo.ogm


I am using the py2neo.ogm api to construct queries of my IssueOGM class based on its relationship to another class.

I can see why this fails:

>>> list(IssueOGM.select(graph).where(
...     "_ -[:HAS_TAG]- (t:TagOGM {tag: 'critical'})"))

Traceback (most recent call last):
...
py2neo.database.status.CypherSyntaxError: Variable `t` not defined (line 1, column 42 (offset: 41))
"MATCH (_:IssueOGM) WHERE _ -[:HAS_TAG]- (t:TagOGM {tag: 'critical'}) RETURN _"

Is there a way using the OGM api to create a filter that is interpreted as this?

"MATCH (_:IssueOGM) -[:HAS_TAG]- (t:TagOGM {tag: 'critical'}) RETURN _"

Solution

  • Like an ORM, the OGM seems to be really good for quickly storing and/or retrieving nodes from your graph, and saving special methods and so forth to make each node 'work' nicely in your application. In this instance, you could use the RelatedFrom class on TagOGM to list all the issues tagged with a particular tag. However, this approach can sometimes lead to making lots of inadvertent db calls without realising (especially in a big application).

    Often for cases like this (where you're looking for a pattern rather than a specific node), I'd recommend just writing a cypher query to get the job done. py2neo.ogm actually makes this remarkably simple, by allowing you to store it as a class method of the GraphObject. In your example, something like the following should work. Writing similar queries in the future will also allow you to search based on much more complex criteria and leverage the functionality of neo4j and cypher to make really complex queries quickly in a single transaction (rather than going back and forth to the db as you manipulate an OGM object).

    from py2neo import GraphObject, Property
    
    class TagOGM(GraphObject):
        name = Property()
    
    class IssueOGM(GraphObject):
        name = Property()
        time = Property()
        description = Property()
    
        @classmethod
        def select_by_tag(cls, tag_name):
            '''
            Returns an OGM instance for every instance tagged a certain way
            '''
            q = 'MATCH (t:TagOGM { name: {tag_name} })<-[:HAS_TAG]-(i:IssueOGM) RETURN i'
            return [
                cls.wrap(row['i'])
                for row in graph.eval(q, { 'tag_name': tag_name }).data()
            ]