0
# Queries
1
2
ODMantic provides a functional query building system using Python operators and functions to construct MongoDB queries and sort expressions.
3
4
## Capabilities
5
6
### Comparison Operators
7
8
Functions for building comparison queries against model fields.
9
10
```python { .api }
11
def eq(field, value):
12
"""
13
Equality comparison.
14
15
Args:
16
field: FieldProxy for the model field
17
value: Value to compare against
18
19
Returns:
20
QueryExpression: MongoDB equality query
21
"""
22
23
def ne(field, value):
24
"""
25
Not equal comparison.
26
27
Args:
28
field: FieldProxy for the model field
29
value: Value to compare against
30
31
Returns:
32
QueryExpression: MongoDB not equal query
33
"""
34
35
def gt(field, value):
36
"""
37
Greater than comparison.
38
39
Args:
40
field: FieldProxy for the model field
41
value: Value to compare against
42
43
Returns:
44
QueryExpression: MongoDB greater than query
45
"""
46
47
def gte(field, value):
48
"""
49
Greater than or equal comparison.
50
51
Args:
52
field: FieldProxy for the model field
53
value: Value to compare against
54
55
Returns:
56
QueryExpression: MongoDB greater than or equal query
57
"""
58
59
def lt(field, value):
60
"""
61
Less than comparison.
62
63
Args:
64
field: FieldProxy for the model field
65
value: Value to compare against
66
67
Returns:
68
QueryExpression: MongoDB less than query
69
"""
70
71
def lte(field, value):
72
"""
73
Less than or equal comparison.
74
75
Args:
76
field: FieldProxy for the model field
77
value: Value to compare against
78
79
Returns:
80
QueryExpression: MongoDB less than or equal query
81
"""
82
```
83
84
### Set Operators
85
86
Functions for set-based queries.
87
88
```python { .api }
89
def in_(field, sequence):
90
"""
91
Value in sequence query.
92
93
Args:
94
field: FieldProxy for the model field
95
sequence: Iterable of values to match against
96
97
Returns:
98
QueryExpression: MongoDB $in query
99
"""
100
101
def not_in(field, sequence):
102
"""
103
Value not in sequence query.
104
105
Args:
106
field: FieldProxy for the model field
107
sequence: Iterable of values to exclude
108
109
Returns:
110
QueryExpression: MongoDB $nin query
111
"""
112
```
113
114
### Pattern Matching
115
116
Functions for pattern and text matching.
117
118
```python { .api }
119
def match(field, pattern):
120
"""
121
Regular expression pattern matching.
122
123
Args:
124
field: FieldProxy for the model field
125
pattern: Regular expression pattern (str or compiled Pattern)
126
127
Returns:
128
QueryExpression: MongoDB regex query
129
"""
130
```
131
132
### Logical Operators
133
134
Functions for combining multiple query expressions.
135
136
```python { .api }
137
def and_(*elements):
138
"""
139
Logical AND of multiple query expressions.
140
141
Args:
142
*elements: QueryExpression objects to combine with AND
143
144
Returns:
145
QueryExpression: MongoDB $and query
146
"""
147
148
def or_(*elements):
149
"""
150
Logical OR of multiple query expressions.
151
152
Args:
153
*elements: QueryExpression objects to combine with OR
154
155
Returns:
156
QueryExpression: MongoDB $or query
157
"""
158
159
def nor_(*elements):
160
"""
161
Logical NOR of multiple query expressions.
162
163
Args:
164
*elements: QueryExpression objects to combine with NOR
165
166
Returns:
167
QueryExpression: MongoDB $nor query
168
"""
169
```
170
171
### Sort Operations
172
173
Functions for building sort expressions.
174
175
```python { .api }
176
def asc(field):
177
"""
178
Ascending sort order.
179
180
Args:
181
field: FieldProxy for the model field
182
183
Returns:
184
SortExpression: MongoDB ascending sort
185
"""
186
187
def desc(field):
188
"""
189
Descending sort order.
190
191
Args:
192
field: FieldProxy for the model field
193
194
Returns:
195
SortExpression: MongoDB descending sort
196
"""
197
```
198
199
### Query Types
200
201
Core query and sort expression types.
202
203
```python { .api }
204
class QueryExpression(dict):
205
"""MongoDB query expression dictionary."""
206
207
class SortExpression(dict):
208
"""MongoDB sort expression dictionary."""
209
```
210
211
## Usage Examples
212
213
### Basic Comparisons
214
215
```python
216
from odmantic import Model, AIOEngine
217
from odmantic.query import eq, ne, gt, gte, lt, lte
218
219
class Product(Model):
220
name: str
221
price: float
222
category: str
223
stock: int
224
225
async def comparison_examples(engine: AIOEngine):
226
# Equality (can also use == operator)
227
expensive = await engine.find(Product, eq(Product.price, 100.0))
228
# Or: expensive = await engine.find(Product, Product.price == 100.0)
229
230
# Not equal
231
not_electronics = await engine.find(Product, ne(Product.category, "electronics"))
232
# Or: not_electronics = await engine.find(Product, Product.category != "electronics")
233
234
# Greater than
235
expensive_items = await engine.find(Product, gt(Product.price, 50.0))
236
# Or: expensive_items = await engine.find(Product, Product.price > 50.0)
237
238
# Less than or equal
239
affordable = await engine.find(Product, lte(Product.price, 25.0))
240
# Or: affordable = await engine.find(Product, Product.price <= 25.0)
241
242
# Range query
243
mid_range = await engine.find(
244
Product,
245
gte(Product.price, 20.0),
246
lte(Product.price, 50.0)
247
)
248
# Or: mid_range = await engine.find(Product, Product.price >= 20.0, Product.price <= 50.0)
249
```
250
251
### Set Operations
252
253
```python
254
from odmantic.query import in_, not_in
255
256
async def set_examples(engine: AIOEngine):
257
# Find products in specific categories
258
tech_products = await engine.find(
259
Product,
260
in_(Product.category, ["electronics", "computers", "phones"])
261
)
262
263
# Exclude out-of-stock items
264
available_products = await engine.find(
265
Product,
266
not_in(Product.stock, [0])
267
)
268
269
# Find products with specific names
270
featured_products = await engine.find(
271
Product,
272
in_(Product.name, ["iPhone", "MacBook", "iPad"])
273
)
274
```
275
276
### Pattern Matching
277
278
```python
279
from odmantic.query import match
280
import re
281
282
async def pattern_examples(engine: AIOEngine):
283
# Find products with names starting with "Pro"
284
pro_products = await engine.find(
285
Product,
286
match(Product.name, r"^Pro")
287
)
288
289
# Case-insensitive search
290
apple_products = await engine.find(
291
Product,
292
match(Product.name, re.compile(r"apple", re.IGNORECASE))
293
)
294
295
# Find products with email pattern in description (if you had a description field)
296
# email_mentions = await engine.find(Product, match(Product.description, r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"))
297
```
298
299
### Logical Operations
300
301
```python
302
from odmantic.query import and_, or_, nor_
303
304
async def logical_examples(engine: AIOEngine):
305
# AND: expensive electronics
306
expensive_electronics = await engine.find(
307
Product,
308
and_(
309
eq(Product.category, "electronics"),
310
gt(Product.price, 100.0)
311
)
312
)
313
314
# OR: either cheap or high stock
315
bargain_or_available = await engine.find(
316
Product,
317
or_(
318
lt(Product.price, 20.0),
319
gt(Product.stock, 100)
320
)
321
)
322
323
# NOR: neither expensive nor out of stock
324
reasonable_available = await engine.find(
325
Product,
326
nor_(
327
gt(Product.price, 200.0),
328
eq(Product.stock, 0)
329
)
330
)
331
332
# Complex nested logical operations
333
complex_query = await engine.find(
334
Product,
335
and_(
336
or_(
337
eq(Product.category, "electronics"),
338
eq(Product.category, "computers")
339
),
340
gt(Product.price, 50.0),
341
gt(Product.stock, 0)
342
)
343
)
344
```
345
346
### Sorting
347
348
```python
349
from odmantic.query import asc, desc
350
351
async def sorting_examples(engine: AIOEngine):
352
# Sort by price ascending
353
cheap_first = await engine.find(Product, sort=asc(Product.price))
354
355
# Sort by price descending
356
expensive_first = await engine.find(Product, sort=desc(Product.price))
357
358
# Multiple sort criteria (tuple of sort expressions)
359
sorted_products = await engine.find(
360
Product,
361
sort=(desc(Product.category), asc(Product.price))
362
)
363
364
# Sort with query
365
electronics_by_price = await engine.find(
366
Product,
367
eq(Product.category, "electronics"),
368
sort=desc(Product.price)
369
)
370
```
371
372
### Complex Query Examples
373
374
```python
375
async def complex_examples(engine: AIOEngine):
376
# Find available, reasonably priced electronics
377
good_electronics = await engine.find(
378
Product,
379
and_(
380
eq(Product.category, "electronics"),
381
gte(Product.price, 10.0),
382
lte(Product.price, 500.0),
383
gt(Product.stock, 0)
384
),
385
sort=asc(Product.price)
386
)
387
388
# Find products that match multiple criteria
389
filtered_products = await engine.find(
390
Product,
391
or_(
392
and_(
393
eq(Product.category, "books"),
394
lt(Product.price, 30.0)
395
),
396
and_(
397
in_(Product.category, ["electronics", "computers"]),
398
gte(Product.stock, 5),
399
lte(Product.price, 200.0)
400
)
401
),
402
sort=(desc(Product.stock), asc(Product.price)),
403
limit=20
404
)
405
406
# Text search with multiple patterns
407
search_results = await engine.find(
408
Product,
409
or_(
410
match(Product.name, r"(?i)(pro|premium|deluxe)"),
411
and_(
412
match(Product.category, r"(?i)electronics"),
413
gt(Product.price, 100.0)
414
)
415
),
416
sort=desc(Product.price)
417
)
418
```
419
420
### Query Building Patterns
421
422
```python
423
def build_product_filter(min_price=None, max_price=None, categories=None, in_stock_only=False):
424
"""Build a dynamic query based on parameters."""
425
conditions = []
426
427
if min_price is not None:
428
conditions.append(gte(Product.price, min_price))
429
430
if max_price is not None:
431
conditions.append(lte(Product.price, max_price))
432
433
if categories:
434
conditions.append(in_(Product.category, categories))
435
436
if in_stock_only:
437
conditions.append(gt(Product.stock, 0))
438
439
if len(conditions) == 1:
440
return conditions[0]
441
elif len(conditions) > 1:
442
return and_(*conditions)
443
else:
444
return {} # No conditions
445
446
async def dynamic_search(engine: AIOEngine):
447
# Use the dynamic filter
448
query = build_product_filter(
449
min_price=20.0,
450
max_price=100.0,
451
categories=["electronics", "books"],
452
in_stock_only=True
453
)
454
455
products = await engine.find(Product, query, sort=asc(Product.price))
456
```
457
458
### Working with Dates and ObjectIds
459
460
```python
461
from datetime import datetime, timedelta
462
from odmantic import ObjectId
463
464
class Order(Model):
465
customer_id: ObjectId
466
created_at: datetime
467
total: float
468
469
async def date_queries(engine: AIOEngine):
470
# Find recent orders
471
week_ago = datetime.utcnow() - timedelta(days=7)
472
recent_orders = await engine.find(
473
Order,
474
gte(Order.created_at, week_ago)
475
)
476
477
# Find orders for specific customer
478
customer_orders = await engine.find(
479
Order,
480
eq(Order.customer_id, ObjectId("507f1f77bcf86cd799439011"))
481
)
482
483
# Find large orders this month
484
month_start = datetime.utcnow().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
485
large_orders = await engine.find(
486
Order,
487
and_(
488
gte(Order.created_at, month_start),
489
gt(Order.total, 500.0)
490
),
491
sort=desc(Order.total)
492
)
493
```