or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bson-types.mdengines.mdfields.mdindex.mdindexes.mdmodels.mdqueries.mdsessions.md

indexes.mddocs/

0

# Indexes

1

2

ODMantic provides index management for MongoDB collections through field-level indexing options and compound index definitions.

3

4

## Capabilities

5

6

### Index Class

7

8

Define compound indexes spanning multiple fields with custom options.

9

10

```python { .api }

11

class Index:

12

"""Compound index definition for MongoDB collections."""

13

14

def __init__(self, *fields, **kwargs):

15

"""

16

Create compound index definition.

17

18

Args:

19

*fields: Field names or (field, direction) tuples

20

**kwargs: Index options (unique, sparse, background, etc.)

21

22

Example:

23

Index("field1", ("field2", -1), unique=True)

24

Index(User.name, User.email, background=True)

25

"""

26

```

27

28

### Reference Function

29

30

Define reference fields that link to other documents.

31

32

```python { .api }

33

def Reference(*, key_name=None):

34

"""

35

Define reference field to another document.

36

37

Args:

38

key_name: MongoDB field name for the reference

39

40

Returns:

41

Field configuration for ObjectId reference

42

"""

43

```

44

45

### Field-Level Indexing

46

47

Index options available in Field definitions.

48

49

```python { .api }

50

# In Field() function:

51

# index=True - Create regular index

52

# unique=True - Create unique index

53

# primary_field=True - Use as primary key (_id)

54

```

55

56

## Usage Examples

57

58

### Single Field Indexes

59

60

```python

61

from odmantic import Model, Field

62

63

class User(Model):

64

# Regular index

65

username: str = Field(index=True)

66

67

# Unique index

68

email: str = Field(unique=True)

69

70

# Both indexed

71

phone: str = Field(index=True, unique=True)

72

73

# Non-indexed fields

74

first_name: str

75

last_name: str

76

age: int

77

78

# The engine will create indexes when configure_database is called

79

async def setup_indexes(engine):

80

await engine.configure_database([User])

81

```

82

83

### Compound Indexes

84

85

```python

86

from odmantic import Model, Index

87

88

class BlogPost(Model):

89

title: str

90

author: str = Field(index=True)

91

category: str = Field(index=True)

92

published_date: datetime

93

view_count: int = 0

94

tags: list[str] = []

95

96

# Define compound indexes

97

model_config = {

98

"collection": "blog_posts",

99

"indexes": [

100

# Compound index on author and published_date

101

Index("author", "published_date"),

102

103

# Compound index with sort direction

104

Index("category", ("published_date", -1)),

105

106

# Unique compound index

107

Index("author", "title", unique=True),

108

109

# Text index for search

110

Index(("title", "text"), ("content", "text")),

111

112

# Sparse index (only indexes documents with the field)

113

Index("tags", sparse=True),

114

]

115

}

116

117

# Alternative way to define indexes using class attribute

118

class Product(Model):

119

name: str

120

category: str

121

price: float

122

brand: str

123

sku: str = Field(unique=True)

124

125

# Define indexes as class attribute

126

__indexes__ = [

127

Index("category", "brand"),

128

Index("price", background=True),

129

Index(("name", "text"), name="text_search_index"),

130

]

131

```

132

133

### Reference Fields

134

135

```python

136

from odmantic import Model, Reference, ObjectId

137

138

class Author(Model):

139

name: str = Field(unique=True)

140

email: str = Field(unique=True)

141

bio: str = ""

142

143

class Book(Model):

144

title: str

145

isbn: str = Field(unique=True)

146

147

# Reference to Author document

148

author_id: ObjectId = Reference()

149

150

# Reference with custom key name

151

publisher_id: ObjectId = Reference(key_name="publisher")

152

153

published_date: datetime

154

page_count: int

155

156

class Review(Model):

157

# Multiple references

158

book_id: ObjectId = Reference()

159

reviewer_id: ObjectId = Reference()

160

161

rating: int = Field(ge=1, le=5)

162

comment: str

163

created_at: datetime = Field(default_factory=datetime.utcnow)

164

165

# Usage

166

async def reference_example(engine):

167

# Create author

168

author = Author(name="Jane Doe", email="jane@example.com")

169

await engine.save(author)

170

171

# Create book with reference to author

172

book = Book(

173

title="Python Patterns",

174

isbn="978-1234567890",

175

author_id=author.id, # Reference using ObjectId

176

publisher_id=ObjectId(), # Some publisher ID

177

published_date=datetime.utcnow(),

178

page_count=300

179

)

180

await engine.save(book)

181

182

# Find books by author

183

author_books = await engine.find(Book, Book.author_id == author.id)

184

```

185

186

### Text Indexes

187

188

```python

189

class Article(Model):

190

title: str

191

content: str

192

author: str

193

tags: list[str] = []

194

195

# Text search index

196

__indexes__ = [

197

# Simple text index

198

Index(("title", "text"), ("content", "text")),

199

200

# Text index with weights

201

Index(

202

("title", "text"),

203

("content", "text"),

204

weights={"title": 10, "content": 5},

205

name="article_text_search"

206

),

207

208

# Combined text and regular index

209

Index("author", ("title", "text")),

210

]

211

212

# Text search usage

213

async def text_search_example(engine):

214

# Configure indexes

215

await engine.configure_database([Article])

216

217

# Text search requires MongoDB's $text operator

218

# ODMantic doesn't have built-in text search functions,

219

# but you can use raw MongoDB queries through the collection

220

collection = engine.get_collection(Article)

221

222

# Raw text search

223

cursor = collection.find({"$text": {"$search": "python programming"}})

224

articles = []

225

async for doc in cursor:

226

article = Article.model_validate_doc(doc)

227

articles.append(article)

228

```

229

230

### Geospatial Indexes

231

232

```python

233

class Location(Model):

234

name: str

235

# GeoJSON point format: [longitude, latitude]

236

coordinates: list[float] = Field(min_items=2, max_items=2)

237

type: str = "Point"

238

239

# 2dsphere index for geospatial queries

240

__indexes__ = [

241

Index(("coordinates", "2dsphere")),

242

Index("name", ("coordinates", "2dsphere")),

243

]

244

245

# Geospatial usage

246

async def geospatial_example(engine):

247

# Create location

248

location = Location(

249

name="Central Park",

250

coordinates=[-73.965355, 40.782865] # [longitude, latitude]

251

)

252

await engine.save(location)

253

254

# Geospatial queries require raw MongoDB operations

255

collection = engine.get_collection(Location)

256

257

# Find locations near a point

258

near_query = {

259

"coordinates": {

260

"$near": {

261

"$geometry": {

262

"type": "Point",

263

"coordinates": [-73.970, 40.780]

264

},

265

"$maxDistance": 1000 # meters

266

}

267

}

268

}

269

270

cursor = collection.find(near_query)

271

nearby_locations = []

272

async for doc in cursor:

273

location = Location.model_validate_doc(doc)

274

nearby_locations.append(location)

275

```

276

277

### Index Management

278

279

```python

280

async def index_management_examples(engine):

281

# Configure database indexes for models

282

models = [User, BlogPost, Product, Article, Location]

283

await engine.configure_database(models)

284

285

# Update existing indexes (use with caution in production)

286

await engine.configure_database(models, update_existing_indexes=True)

287

288

# Get raw collection for manual index operations

289

collection = engine.get_collection(User)

290

291

# List all indexes

292

indexes = await collection.list_indexes().to_list(None)

293

for index in indexes:

294

print(f"Index: {index}")

295

296

# Create index manually if needed

297

await collection.create_index([("custom_field", 1)], background=True)

298

299

# Drop index manually if needed

300

await collection.drop_index("custom_field_1")

301

```

302

303

### Performance Considerations

304

305

```python

306

class OptimizedModel(Model):

307

# Frequently queried fields should be indexed

308

user_id: ObjectId = Field(index=True)

309

status: str = Field(index=True)

310

created_at: datetime = Field(index=True, default_factory=datetime.utcnow)

311

312

# Compound index for common query patterns

313

__indexes__ = [

314

# For queries like: status="active" AND created_at > date

315

Index("status", ("created_at", -1)),

316

317

# For queries like: user_id=X AND status="active"

318

Index("user_id", "status"),

319

320

# Background index creation (non-blocking)

321

Index("some_large_field", background=True),

322

323

# Sparse index (only for documents with the field)

324

Index("optional_field", sparse=True),

325

326

# Partial index with filter expression

327

Index(

328

"filtered_field",

329

partialFilterExpression={"filtered_field": {"$exists": True}}

330

),

331

]

332

333

# Index strategy guidelines:

334

def index_strategy_example():

335

"""

336

Index Strategy Guidelines:

337

338

1. Index fields used in WHERE clauses frequently

339

2. Create compound indexes for multi-field queries

340

3. Order compound index fields by selectivity (most selective first)

341

4. Use sparse indexes for optional fields

342

5. Use background=True for large collections

343

6. Monitor index usage and remove unused indexes

344

7. Consider partial indexes for conditional queries

345

"""

346

347

# Good compound index order (high to low selectivity)

348

# Index("user_id", "status", "date") # user_id is most selective

349

350

# Bad compound index order

351

# Index("status", "user_id", "date") # status has few unique values

352

```

353

354

### Custom Index Options

355

356

```python

357

class AdvancedIndexModel(Model):

358

name: str

359

data: dict = {}

360

expires_at: datetime

361

362

__indexes__ = [

363

# TTL index (documents auto-expire)

364

Index("expires_at", expireAfterSeconds=3600),

365

366

# Case-insensitive index

367

Index("name", collation={"locale": "en", "strength": 2}),

368

369

# Partial index with complex filter

370

Index(

371

"data.important_field",

372

partialFilterExpression={

373

"data.important_field": {"$exists": True, "$ne": None}

374

},

375

sparse=True

376

),

377

378

# Named index for reference

379

Index("name", "data.category", name="name_category_idx"),

380

381

# Index with custom options

382

Index(

383

("name", "text"),

384

default_language="english",

385

language_override="lang_field"

386

),

387

]

388

```