1

Suppose I have the following models from the neomodel documentation.

class FriendRel(StructuredRel):
    since = DateTimeProperty(
        default=lambda: datetime.now(pytz.utc)
    )
    met = StringProperty()

class Person(StructuredNode):
    name = StringProperty()
    friends = RelationshipTo('Person', 'FRIEND', model=FriendRel)

And I create the following data.

bob = Person(name='bob').save()
frank = Person(name='frank').save()
rel = bob.friends.connect(frank, {'since': dt.datetime.now(), 'met': 'Germany'})

Now my question is how I should go about retrieving both the friends of an object and the corresponding FriendshipRel objects between those relationships.

The Neomodel docs seem to say to do the following.

>>> bob = Person.nodes.get(name='bob')
>>> frank = bob.friends[0]  # get bob's friend frank using database query?
>>> rel = bob.friends.relationship(frank)  # query database again?
>>> rel.met
'Germany'

When doing this, it really feels like there would be a better way of retrieving relationship objects without another database query. I would expect these relationship objects to already be cached when you retrieve a node's friends?

So in a loop, would this be the best way to retrieve all of a Person's friends and the FriendshipRel objects for those friendships?

# source: https://stackoverflow.com/questions/67821341/retrieve-the-relationship-object-in-neomodel 
for friend in bob.friends:
    rel = bob.friends.relationship(friend)

This seems quite inefficient, as doesn't it require another database query for each relationship? Or am I not understanding correctly?

With cypher, I would just do the following:

MATCH(i:Person{name: 'bob'})-[j:FRIEND]->(k)  RETURN i,j,k

So my question: is there a way, using neomodel, to retrieve a node's relationships and the objects for those relationships both at the same time?

Ethan Posner
  • 343
  • 1
  • 2
  • 14

1 Answers1

1

I've checked the neomodel source code and there doesn't seem to be a way to achieve what I want in a more efficient way than what I found in this stackoverflow answer.

But I now know how to do this using cypher queries like so:

from neomodel import db
from models import Person, FriendRel

bob = Person.nodes.get(name='bob')

# Only one database query. Yay!
results, cols = db.cypher_query(f"""MATCH (node)-[rel]-(neighbor)
                                    WHERE id(node)={john.id}
                                    RETURN node, rel, neighbor""")

rels = {}  # friendships mapped to neighbor node ids
neighbors = []

for row in results:
    neighbor = Person.inflate(row[cols.index('neighbor')])
    neighbors.append(neighbor)
    rel = FriendRel.inflate(row[cols.index('rel')])
    rels[neighbor.id] = rel

Then, now that you've stored all neighbors and the relationships between them, you can loop through them like so:

for neighbor, rel in rels:
    print(f"bob has a friendship with {neighbor}.")
    print(f"They've been friends since {rel.since}")

Or like so:

for neighbor in neighbors:
    rel = rels[neighbor.id]

Thanks to everyone's helpful advice!

Ethan Posner
  • 343
  • 1
  • 2
  • 14