0
# Query and Traversal
1
2
Advanced querying capabilities in neomodel including filtering, ordering, aggregation, and graph traversal operations. Supports complex WHERE clauses, relationship navigation, and both synchronous and asynchronous query patterns.
3
4
## Capabilities
5
6
### NodeSet Query Builder
7
8
Primary interface for querying and filtering node collections with chainable methods.
9
10
```python { .api }
11
class NodeSet:
12
"""
13
Query builder for node collections in synchronous mode.
14
15
Provides filtering, ordering, limiting, and aggregation capabilities.
16
"""
17
18
def filter(self, **kwargs):
19
"""
20
Filter nodes by property values and relationships.
21
22
Args:
23
**kwargs: Filter criteria using Django-style lookups
24
(exact, contains, icontains, startswith, endswith,
25
gt, gte, lt, lte, in, isnull, regex, iregex)
26
27
Returns:
28
NodeSet: Filtered node collection
29
"""
30
31
def exclude(self, **kwargs):
32
"""
33
Exclude nodes matching criteria.
34
35
Args:
36
**kwargs: Exclusion criteria using Django-style lookups
37
38
Returns:
39
NodeSet: Filtered node collection
40
"""
41
42
def get(self, **kwargs):
43
"""
44
Get a single node matching criteria.
45
46
Args:
47
**kwargs: Filter criteria
48
49
Returns:
50
Node instance
51
52
Raises:
53
DoesNotExist: If no node matches
54
MultipleNodesReturned: If multiple nodes match
55
"""
56
57
def get_or_none(self, **kwargs):
58
"""
59
Get a single node or None if not found.
60
61
Args:
62
**kwargs: Filter criteria
63
64
Returns:
65
Node instance or None
66
"""
67
68
def all(self):
69
"""
70
Get all nodes in the collection.
71
72
Returns:
73
list: List of node instances
74
"""
75
76
def order_by(self, *properties):
77
"""
78
Order results by properties.
79
80
Args:
81
*properties: Property names, prefix with '-' for descending
82
83
Returns:
84
NodeSet: Ordered node collection
85
"""
86
87
def limit(self, count):
88
"""
89
Limit the number of results.
90
91
Args:
92
count (int): Maximum number of results
93
94
Returns:
95
NodeSet: Limited node collection
96
"""
97
98
def skip(self, count):
99
"""
100
Skip a number of results.
101
102
Args:
103
count (int): Number of results to skip
104
105
Returns:
106
NodeSet: Node collection with offset
107
"""
108
109
class AsyncNodeSet:
110
"""
111
Query builder for node collections in asynchronous mode.
112
113
Same interface as NodeSet but all methods are async.
114
"""
115
116
async def filter(self, **kwargs):
117
"""Asynchronously filter nodes by property values and relationships."""
118
119
async def exclude(self, **kwargs):
120
"""Asynchronously exclude nodes matching criteria."""
121
122
async def get(self, **kwargs):
123
"""Asynchronously get a single node matching criteria."""
124
125
async def get_or_none(self, **kwargs):
126
"""Asynchronously get a single node or None if not found."""
127
128
async def all(self):
129
"""Asynchronously get all nodes in the collection."""
130
131
def order_by(self, *properties):
132
"""Order results by properties (returns modified NodeSet)."""
133
134
def limit(self, count):
135
"""Limit the number of results (returns modified NodeSet)."""
136
137
def skip(self, count):
138
"""Skip a number of results (returns modified NodeSet)."""
139
```
140
141
### Q Objects for Complex Queries
142
143
Query objects for building complex logical queries with AND, OR, and NOT operations.
144
145
```python { .api }
146
class Q:
147
"""
148
Query object for complex filtering with logical operators.
149
150
Supports combining multiple filter conditions with AND, OR, and NOT logic.
151
"""
152
153
def __init__(self, **kwargs):
154
"""
155
Initialize Q object with filter criteria.
156
157
Args:
158
**kwargs: Filter criteria using Django-style lookups
159
"""
160
161
def __and__(self, other):
162
"""
163
Combine with another Q object using AND logic.
164
165
Args:
166
other (Q): Another Q object
167
168
Returns:
169
Q: Combined Q object
170
"""
171
172
def __or__(self, other):
173
"""
174
Combine with another Q object using OR logic.
175
176
Args:
177
other (Q): Another Q object
178
179
Returns:
180
Q: Combined Q object
181
"""
182
183
def __invert__(self):
184
"""
185
Negate the Q object (NOT logic).
186
187
Returns:
188
Q: Negated Q object
189
"""
190
```
191
192
### Traversal Classes
193
194
Classes for advanced graph traversal and path-based operations.
195
196
```python { .api }
197
class Traversal:
198
"""
199
Graph traversal operations for synchronous mode.
200
201
Enables complex path-based queries and graph navigation.
202
"""
203
204
def traverse(self, *relationships):
205
"""
206
Traverse relationships to connected nodes.
207
208
Args:
209
*relationships: Relationship definitions to follow
210
211
Returns:
212
Traversal: Extended traversal path
213
"""
214
215
class AsyncTraversal:
216
"""
217
Graph traversal operations for asynchronous mode.
218
219
Same interface as Traversal but for async operations.
220
"""
221
222
def traverse(self, *relationships):
223
"""
224
Traverse relationships to connected nodes asynchronously.
225
226
Args:
227
*relationships: Relationship definitions to follow
228
229
Returns:
230
AsyncTraversal: Extended traversal path
231
"""
232
```
233
234
### Path Classes
235
236
Classes representing paths through the graph with node and relationship sequences.
237
238
```python { .api }
239
class NeomodelPath:
240
"""
241
Represents Neo4j paths in synchronous mode.
242
243
Contains sequences of nodes and relationships forming a path through the graph.
244
"""
245
246
def nodes(self):
247
"""
248
Get nodes in the path.
249
250
Returns:
251
list: List of node instances in path order
252
"""
253
254
def relationships(self):
255
"""
256
Get relationships in the path.
257
258
Returns:
259
list: List of relationship instances in path order
260
"""
261
262
class AsyncNeomodelPath:
263
"""
264
Represents Neo4j paths in asynchronous mode.
265
266
Same interface as NeomodelPath but for async operations.
267
"""
268
269
def nodes(self):
270
"""Get nodes in the path."""
271
272
def relationships(self):
273
"""Get relationships in the path."""
274
```
275
276
## Usage Examples
277
278
### Basic Filtering and Querying
279
280
```python
281
from neomodel import StructuredNode, StringProperty, IntegerProperty
282
283
class Person(StructuredNode):
284
name = StringProperty(required=True)
285
age = IntegerProperty()
286
email = StringProperty()
287
288
# Basic filtering
289
adults = Person.nodes.filter(age__gte=18)
290
johns = Person.nodes.filter(name__icontains='john')
291
gmail_users = Person.nodes.filter(email__endswith='@gmail.com')
292
293
# Exclusion
294
non_admins = Person.nodes.exclude(email__endswith='@admin.com')
295
296
# Ordering and limiting
297
recent_users = Person.nodes.order_by('-created_at').limit(10)
298
alphabetical = Person.nodes.order_by('name')
299
300
# Get single node
301
alice = Person.nodes.get(name='Alice')
302
maybe_bob = Person.nodes.get_or_none(name='Bob')
303
```
304
305
### Complex Queries with Q Objects
306
307
```python
308
from neomodel import Q
309
310
# Complex logical conditions
311
young_or_senior = Person.nodes.filter(
312
Q(age__lt=25) | Q(age__gt=65)
313
)
314
315
# Multiple conditions
316
tech_professionals = Person.nodes.filter(
317
Q(email__endswith='@tech.com') &
318
Q(age__gte=25) &
319
Q(age__lte=45)
320
)
321
322
# Negation
323
non_gmail_adults = Person.nodes.filter(
324
~Q(email__endswith='@gmail.com') & Q(age__gte=18)
325
)
326
327
# Combining with regular filters
328
filtered_users = Person.nodes.filter(
329
Q(name__startswith='A') | Q(name__startswith='B'),
330
age__gte=21
331
)
332
```
333
334
### Advanced Filter Lookups
335
336
```python
337
# String lookups
338
exact_match = Person.nodes.filter(name='Alice')
339
contains = Person.nodes.filter(name__contains='ali')
340
case_insensitive = Person.nodes.filter(name__icontains='ALICE')
341
starts_with = Person.nodes.filter(name__startswith='Al')
342
ends_with = Person.nodes.filter(name__endswith='ice')
343
344
# Numeric comparisons
345
young = Person.nodes.filter(age__lt=30)
346
adults = Person.nodes.filter(age__gte=18)
347
middle_aged = Person.nodes.filter(age__gt=30, age__lt=50)
348
349
# List membership
350
names = ['Alice', 'Bob', 'Charlie']
351
selected_people = Person.nodes.filter(name__in=names)
352
353
# Null checks
354
has_email = Person.nodes.filter(email__isnull=False)
355
no_age = Person.nodes.filter(age__isnull=True)
356
357
# Regular expressions
358
phone_pattern = Person.nodes.filter(phone__regex=r'^\+1\d{10}$')
359
```
360
361
### Async Query Operations
362
363
```python
364
from neomodel import AsyncStructuredNode
365
366
class AsyncPerson(AsyncStructuredNode):
367
name = StringProperty(required=True)
368
age = IntegerProperty()
369
370
async def query_people():
371
# Async filtering
372
adults = await AsyncPerson.nodes.filter(age__gte=18).all()
373
alice = await AsyncPerson.nodes.get(name='Alice')
374
375
# Async ordering and limiting
376
recent = await AsyncPerson.nodes.order_by('-created_at').limit(5).all()
377
378
return adults, alice, recent
379
```
380
381
### Relationship-based Queries
382
383
```python
384
class Person(StructuredNode):
385
name = StringProperty(required=True)
386
friends = RelationshipTo('Person', 'FRIENDS_WITH')
387
works_at = RelationshipTo('Company', 'WORKS_AT')
388
389
class Company(StructuredNode):
390
name = StringProperty(required=True)
391
392
# Query through relationships
393
alice = Person.nodes.get(name='Alice')
394
395
# Get all friends
396
alice_friends = alice.friends.all()
397
398
# Filter friends
399
close_friends = alice.friends.filter(name__contains='Bob')
400
401
# Query company employees
402
company = Company.nodes.get(name='TechCorp')
403
employees = company.employees.all()
404
405
# Complex relationship filtering
406
tech_workers = Person.nodes.filter(works_at__name='TechCorp')
407
```
408
409
### Graph Traversal Operations
410
411
```python
412
# Traversal through multiple relationship types
413
alice = Person.nodes.get(name='Alice')
414
415
# Traverse friend-of-friend relationships
416
friends_of_friends = alice.traverse('friends', 'friends').all()
417
418
# Complex path traversals
419
path_results = alice.traverse('works_at', 'employees').filter(age__gt=30)
420
421
# Path objects (when supported)
422
paths = alice.traverse_paths('friends').all()
423
for path in paths:
424
nodes = path.nodes()
425
relationships = path.relationships()
426
```
427
428
### Aggregation and Statistics
429
430
```python
431
# Count results
432
total_users = Person.nodes.count()
433
adult_count = Person.nodes.filter(age__gte=18).count()
434
435
# Check existence
436
has_admin = Person.nodes.filter(email__endswith='@admin.com').exists()
437
438
# First/last
439
oldest = Person.nodes.order_by('-age').first()
440
newest = Person.nodes.order_by('-created_at').first()
441
```
442
443
## Types
444
445
```python { .api }
446
# Query result types
447
NodeCollection = List[StructuredNode]
448
SingleNodeResult = Union[StructuredNode, None]
449
450
# Query filter types
451
FilterLookup = Union[str, int, float, bool, list]
452
QueryDict = Dict[str, FilterLookup]
453
454
# Traversal types
455
PathResult = Union[NeomodelPath, AsyncNeomodelPath]
456
TraversalResult = Union[NodeCollection, PathResult]
457
```