Querying

Querying should be easy for anyone familiar with Django. Model managers return a subclass of QuerySet that converts queries into the Cypher graph query language, which yield NodeModel instances on execution.

Most of the Django QuerySet API is implemented, with exceptions noted in the project issues. We’ve added two field lookups- member and member_in- to make searching over array properties easier. For an OnlinePerson instance with an emails property, query against the field like:

OnlinePerson.objects.filter(emails__member="wicked_cool_email@example.com")

Loading a Subgraph

It’s important to remember that, since we’re using a graph database, “JOIN-like” operations are much less expensive. Consider a more connected model:

class FamilyPerson(Person):
    parents = Relationship('self', rel_type='child_of')
    stepdad = Relationship('self', rel_type='step_child_of', single=True)
    siblings = Relationship('self', rel_type='sibling_of')
    # hopefully this is one-to-one...
    spouse = Relationship('self', rel_type='married_to', single=True, rel_single=True)

Finding a child with parents named Tom and Meagan and a stepdad named Jack is simple:

FamilyPerson.objects.filter(parents__name__in=['Tom','Meagan']).filter(stepdad__name='Jack')

If we’d like to pre-load a subgraph around a particular FamilyPerson, we can use select_related():

jack = Person.objects.filter(name='Jack').select_related(depth=5)
#OR
Person.objects.get(name='Jack').select_related('spouse__mother__sister__son__stepdad')

...either of which will pre-load Jack’s extended family so he can go about recalling names without hitting the database a million times.