or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdchange-feeds.mddatabase-management.mddocument-operations.mderror-handling.mdhttp-adapters.mdindex.mdquery-indexing.mdreplication.mdscheduler-monitoring.mdsecurity-document.mdviews-design-documents.md

query-indexing.mddocs/

0

# Query and Indexing

1

2

Query documents using Cloudant Query (Mango) with comprehensive indexing support including JSON indexes, text search, and special indexes with pagination and partitioning capabilities.

3

4

## Capabilities

5

6

### Query Class

7

8

Execute queries using Cloudant Query (Mango) syntax.

9

10

```python { .api }

11

class Query:

12

"""

13

Cloudant query interface using Mango query language.

14

"""

15

16

def __init__(self, database, selector=None, fields=None, **kwargs):

17

"""

18

Initialize query builder.

19

20

Parameters:

21

- database (CloudantDatabase): Target database

22

- selector (dict): Query selector (WHERE clause)

23

- fields (list[str]): Fields to return (SELECT clause)

24

- sort (list[dict]): Sort specification

25

- limit (int): Maximum results

26

- skip (int): Number of results to skip

27

- bookmark (str): Pagination bookmark

28

- use_index (str | list): Index to use for query

29

- execution_stats (bool): Include execution statistics

30

"""

31

32

def __call__(self, **kwargs):

33

"""

34

Execute query with optional parameter overrides.

35

36

Parameters:

37

- **kwargs: Query parameters to override

38

39

Returns:

40

QueryResult: Query result iterator with bookmark support

41

"""

42

43

def custom_result(self, **options):

44

"""

45

Execute query with custom result options.

46

47

Parameters:

48

- **options: Result collection options

49

50

Returns:

51

QueryResult: Custom result iterator

52

"""

53

54

@property

55

def result(self):

56

"""Default query result collection"""

57

```

58

59

### Database Query Methods

60

61

Direct query execution methods on database instances.

62

63

```python { .api }

64

class CouchDatabase(dict):

65

"""Database query methods."""

66

67

def get_query_result(self, selector, fields=None, raw_result=False, **kwargs):

68

"""

69

Execute Cloudant Query and return results.

70

71

Parameters:

72

- selector (dict): Query selector using MongoDB-style syntax

73

- fields (list[str]): Fields to return in results

74

- raw_result (bool): Return raw response without processing

75

- sort (list[dict]): Sort specification [{"field": "asc|desc"}]

76

- limit (int): Maximum number of results

77

- skip (int): Number of results to skip

78

- bookmark (str): Pagination bookmark from previous query

79

- use_index (str | list): Force use of specific index

80

- execution_stats (bool): Include query execution statistics

81

82

Returns:

83

QueryResult | dict: Query results or raw response

84

85

Raises:

86

CloudantDatabaseException: Query execution failed

87

"""

88

89

def get_partitioned_query_result(self, partition_key, selector, fields=None, raw_result=False, **kwargs):

90

"""

91

Execute query within a specific partition.

92

93

Parameters:

94

- partition_key (str): Partition identifier

95

- selector (dict): Query selector

96

- fields (list[str]): Fields to return

97

- raw_result (bool): Return raw response

98

- **kwargs: Same options as get_query_result()

99

100

Returns:

101

QueryResult | dict: Partitioned query results

102

"""

103

```

104

105

### Index Management

106

107

Create and manage indexes for query optimization.

108

109

```python { .api }

110

class CouchDatabase(dict):

111

"""Index management methods."""

112

113

def get_query_indexes(self, raw_result=False):

114

"""

115

List all query indexes in the database.

116

117

Parameters:

118

- raw_result (bool): Return raw response

119

120

Returns:

121

list[dict] | dict: Index definitions or raw response

122

"""

123

124

def create_query_index(self, design_document_id=None, index_name=None, index_type='json', partitioned=None, **kwargs):

125

"""

126

Create a query index.

127

128

Parameters:

129

- design_document_id (str): Design document ID for index

130

- index_name (str): Name for the index

131

- index_type (str): Index type ('json', 'text', 'special')

132

- partitioned (bool): Whether index is partitioned

133

- fields (list[str | dict]): Fields to index

134

- selector (dict): Partial filter selector for index

135

136

Returns:

137

dict: Index creation response

138

139

Raises:

140

CloudantIndexException: Index creation failed

141

"""

142

143

def delete_query_index(self, design_document_id, index_type, index_name):

144

"""

145

Delete a query index.

146

147

Parameters:

148

- design_document_id (str): Design document containing index

149

- index_type (str): Type of index to delete

150

- index_name (str): Name of index to delete

151

152

Returns:

153

dict: Deletion response

154

155

Raises:

156

CloudantIndexException: Index deletion failed

157

"""

158

```

159

160

### Index Classes

161

162

Object-oriented index management.

163

164

```python { .api }

165

class Index:

166

"""

167

JSON query index management.

168

"""

169

170

def __init__(self, database, design_document_id=None, name=None, partitioned=None, **kwargs):

171

"""

172

Initialize index instance.

173

174

Parameters:

175

- database (CloudantDatabase): Target database

176

- design_document_id (str): Design document ID

177

- name (str): Index name

178

- partitioned (bool): Partitioned index flag

179

- fields (list[str | dict]): Fields to index

180

- selector (dict): Partial filter selector

181

"""

182

183

def create(self):

184

"""

185

Create index in database.

186

187

Returns:

188

dict: Creation response

189

190

Raises:

191

CloudantIndexException: Creation failed

192

"""

193

194

def delete(self):

195

"""

196

Delete index from database.

197

198

Returns:

199

dict: Deletion response

200

201

Raises:

202

CloudantIndexException: Deletion failed

203

"""

204

205

@property

206

def index_url(self):

207

"""Index URL endpoint"""

208

209

@property

210

def design_document_id(self):

211

"""Design document ID containing index"""

212

213

@property

214

def name(self):

215

"""Index name"""

216

217

@property

218

def type(self):

219

"""Index type ('json', 'text', 'special')"""

220

221

class TextIndex(Index):

222

"""

223

Text search index for full-text search capabilities.

224

"""

225

226

class SpecialIndex(Index):

227

"""

228

Special index for built-in indexes like _all_docs.

229

"""

230

```

231

232

### Result Collections

233

234

Sliceable, key-accessible, and iterable result collections for efficient data access and pagination.

235

236

```python { .api }

237

class Result:

238

"""

239

Key accessible, sliceable, and iterable interface to result collections.

240

241

Supports efficient paged iteration and flexible data access patterns

242

including index-based access, key-based access, and slicing.

243

"""

244

245

def __init__(self, method_ref, **options):

246

"""

247

Initialize result collection.

248

249

Parameters:

250

- method_ref: Callable that returns JSON result data

251

- descending (bool): Return documents in descending key order

252

- endkey: Stop returning records at specified key

253

- endkey_docid (str): Stop at specified document ID

254

- group (bool): Group reduce results

255

- group_level (int): Group level for complex keys

256

- include_docs (bool): Include full document content

257

- inclusive_end (bool): Include rows with endkey

258

- key: Return only documents matching specified key

259

- keys (list): Return only documents matching specified keys

260

- limit (int): Maximum number of results

261

- page_size (int): Page size for iteration (default: 100)

262

- reduce (bool): Use reduce function

263

- skip (int): Skip specified number of rows

264

- stable (bool): Use stable set of shards

265

- stale (str): Allow stale results ('ok' or 'update_after')

266

- startkey: Start returning records from specified key

267

- startkey_docid (str): Start from specified document ID

268

- update (str): Update view before/after response ('true', 'false', 'lazy')

269

"""

270

271

def __getitem__(self, arg):

272

"""

273

Key access and slicing support.

274

275

Parameters:

276

- arg (int): Index access - skip N records, get next

277

- arg (str | list | ResultByKey): Key access - get records matching key

278

- arg (slice): Slice access - get range of records

279

280

Returns:

281

list: Rows data in JSON format

282

"""

283

284

def __iter__(self):

285

"""

286

Iterate over result collection with automatic pagination.

287

288

Yields:

289

dict: Individual result documents

290

"""

291

292

def all(self):

293

"""

294

Retrieve all results as a list.

295

296

Returns:

297

list: All result documents

298

"""

299

300

class ResultByKey:

301

"""

302

Wrapper for values used to retrieve records by document key.

303

304

Distinguishes between index access and key access when key is numeric.

305

"""

306

307

def __init__(self, value):

308

"""

309

Initialize key wrapper.

310

311

Parameters:

312

- value: The key value to match against

313

"""

314

315

def __call__(self):

316

"""

317

Get the wrapped key value.

318

319

Returns:

320

The original key value

321

"""

322

323

class QueryResult(Result):

324

"""

325

Specialized result collection for Cloudant Query results.

326

327

Extends Result with query-specific iteration using bookmarks

328

and index-only access patterns.

329

"""

330

331

def __init__(self, query, **options):

332

"""

333

Initialize query result collection.

334

335

Parameters:

336

- query: Query callable reference

337

- bookmark (str): Pagination bookmark

338

- fields (list[str]): Fields to return

339

- page_size (int): Page size for iteration (default: 100)

340

- r (int): Read quorum for results

341

- selector (dict): Query selector criteria

342

- sort (list): Sort specification

343

- use_index (str): Specific index to use

344

"""

345

346

def __getitem__(self, arg):

347

"""

348

Index-only access and slicing for query results.

349

350

Parameters:

351

- arg (int): Index access only

352

- arg (slice): Index slice only (no key-based slicing)

353

354

Returns:

355

list: Document data in JSON format

356

357

Raises:

358

ResultException: If key-based access attempted

359

"""

360

```

361

362

### Search Capabilities (Cloudant)

363

364

Full-text search using Lucene indexes.

365

366

```python { .api }

367

class CloudantDatabase(CouchDatabase):

368

"""Search methods."""

369

370

def get_search_result(self, ddoc_id, index_name, **query_params):

371

"""

372

Execute full-text search query.

373

374

Parameters:

375

- ddoc_id (str): Design document ID containing search index

376

- index_name (str): Search index name

377

- q (str): Lucene query string

378

- bookmark (str): Pagination bookmark

379

- limit (int): Maximum results

380

- sort (str | list): Sort specification

381

- include_docs (bool): Include document content

382

- include_fields (list[str]): Specific fields to include

383

- ranges (dict): Numeric range facets

384

- counts (list[str]): String facet counts

385

- drilldown (list[list]): Facet drill-down

386

- group_field (str): Group results by field

387

- group_limit (int): Results per group

388

- group_sort (str | list): Sort within groups

389

390

Returns:

391

dict: Search results with hits, facets, and metadata

392

393

Raises:

394

CloudantDatabaseException: Search failed

395

"""

396

397

def get_partitioned_search_result(self, partition_key, ddoc_id, index_name, **query_params):

398

"""

399

Execute search within specific partition.

400

401

Parameters:

402

- partition_key (str): Partition identifier

403

- ddoc_id (str): Design document ID

404

- index_name (str): Search index name

405

- **query_params: Same options as get_search_result()

406

407

Returns:

408

dict: Partitioned search results

409

"""

410

```

411

412

## Usage Examples

413

414

### Basic Queries

415

416

```python

417

from cloudant import cloudant

418

419

with cloudant('user', 'pass', account='myaccount') as client:

420

db = client['my_database']

421

422

# Simple equality query

423

selector = {'type': 'user', 'status': 'active'}

424

result = db.get_query_result(selector)

425

426

for doc in result:

427

print(f"Active user: {doc['name']}")

428

429

# Query with specific fields

430

fields = ['_id', 'name', 'email']

431

result = db.get_query_result(selector, fields=fields)

432

433

for doc in result:

434

print(f"User: {doc['name']} ({doc['email']})")

435

```

436

437

### Complex Queries

438

439

```python

440

from cloudant import cloudant

441

442

with cloudant('user', 'pass', account='myaccount') as client:

443

db = client['my_database']

444

445

# Range and comparison operators

446

selector = {

447

'type': 'order',

448

'total': {'$gt': 100, '$lt': 1000},

449

'status': {'$in': ['pending', 'processing']},

450

'created_date': {'$gte': '2023-01-01'}

451

}

452

453

# Sort by total descending, then by date ascending

454

sort = [{'total': 'desc'}, {'created_date': 'asc'}]

455

456

result = db.get_query_result(

457

selector=selector,

458

sort=sort,

459

limit=50,

460

fields=['_id', 'total', 'status', 'created_date']

461

)

462

463

for doc in result:

464

print(f"Order {doc['_id']}: ${doc['total']} - {doc['status']}")

465

466

# Text search with regex

467

selector = {

468

'name': {'$regex': '(?i)john.*'}, # Case-insensitive regex

469

'tags': {'$all': ['developer', 'python']}

470

}

471

472

result = db.get_query_result(selector)

473

```

474

475

### Query Object Usage

476

477

```python

478

from cloudant import cloudant

479

from cloudant.query import Query

480

481

with cloudant('user', 'pass', account='myaccount') as client:

482

db = client['my_database']

483

484

# Create reusable query

485

user_query = Query(

486

db,

487

selector={'type': 'user'},

488

fields=['_id', 'name', 'email', 'created_date'],

489

sort=[{'created_date': 'desc'}]

490

)

491

492

# Execute with default parameters

493

recent_users = user_query()

494

for user in recent_users:

495

print(f"User: {user['name']}")

496

497

# Execute with parameter overrides

498

active_users = user_query(

499

selector={'type': 'user', 'status': 'active'},

500

limit=10

501

)

502

503

for user in active_users:

504

print(f"Active user: {user['name']}")

505

```

506

507

### Index Management

508

509

```python

510

from cloudant import cloudant

511

from cloudant.index import Index, TextIndex

512

513

with cloudant('user', 'pass', account='myaccount') as client:

514

db = client['my_database']

515

516

# List existing indexes

517

indexes = db.get_query_indexes()

518

for idx in indexes['indexes']:

519

print(f"Index: {idx['name']} on {idx['def']['fields']}")

520

521

# Create JSON index

522

db.create_query_index(

523

fields=['type', 'status', 'created_date'],

524

index_name='type_status_date_idx'

525

)

526

527

# Create partial index with selector

528

db.create_query_index(

529

fields=['email'],

530

index_name='user_email_idx',

531

selector={'type': 'user'} # Only index user documents

532

)

533

534

# Using Index class

535

user_index = Index(

536

db,

537

name='user_search_idx',

538

fields=['name', 'email', {'created_date': 'desc'}]

539

)

540

user_index.create()

541

542

# Create text search index

543

search_index = TextIndex(

544

db,

545

name='content_search',

546

fields=[

547

{'name': 'title', 'type': 'string'},

548

{'name': 'content', 'type': 'string'},

549

{'name': 'tags', 'type': 'string'}

550

]

551

)

552

search_index.create()

553

554

# Delete index

555

db.delete_query_index('_design/user_search_idx', 'json', 'user_search_idx')

556

```

557

558

### Pagination

559

560

```python

561

from cloudant import cloudant

562

563

with cloudant('user', 'pass', account='myaccount') as client:

564

db = client['my_database']

565

566

selector = {'type': 'product'}

567

limit = 25

568

bookmark = None

569

page = 1

570

571

while True:

572

result = db.get_query_result(

573

selector=selector,

574

limit=limit,

575

bookmark=bookmark,

576

sort=[{'name': 'asc'}]

577

)

578

579

docs = list(result)

580

if not docs:

581

break

582

583

print(f"Page {page}: {len(docs)} products")

584

for doc in docs:

585

print(f" - {doc['name']}")

586

587

# Get bookmark for next page

588

if hasattr(result, 'bookmark'):

589

bookmark = result.bookmark

590

if not bookmark: # No more pages

591

break

592

else:

593

break

594

595

page += 1

596

```

597

598

### Text Search (Cloudant)

599

600

```python

601

from cloudant import cloudant

602

603

with cloudant('user', 'pass', account='myaccount') as client:

604

db = client['my_database']

605

606

# Simple text search

607

search_result = db.get_search_result(

608

'content_ddoc',

609

'content_search',

610

q='python AND database',

611

limit=20,

612

include_docs=True

613

)

614

615

print(f"Found {search_result['total_rows']} matches")

616

for hit in search_result['rows']:

617

doc = hit['doc']

618

print(f"Match: {doc['title']} (score: {hit['order'][0]})")

619

620

# Advanced search with facets

621

search_result = db.get_search_result(

622

'content_ddoc',

623

'content_search',

624

q='*:*', # Match all documents

625

counts=['category', 'author'], # Facet counts

626

ranges={'price': {'low': '[0 TO 50]', 'high': '[50 TO *]'}},

627

drilldown=[['category', 'electronics']], # Filter by category

628

group_field='author',

629

group_limit=3

630

)

631

632

# Display facets

633

for facet_name, counts in search_result.get('counts', {}).items():

634

print(f"{facet_name} facets:")

635

for value, count in counts.items():

636

print(f" {value}: {count}")

637

```

638

639

### Partitioned Queries (Cloudant)

640

641

```python

642

from cloudant import cloudant

643

644

with cloudant('user', 'pass', account='myaccount') as client:

645

# Use partitioned database

646

db = client['partitioned_database']

647

648

# Query within specific partition

649

result = db.get_partitioned_query_result(

650

'user123',

651

selector={'type': 'activity'},

652

sort=[{'timestamp': 'desc'}],

653

limit=10

654

)

655

656

for activity in result:

657

print(f"Activity: {activity['action']} at {activity['timestamp']}")

658

659

# Search within partition

660

search_result = db.get_partitioned_search_result(

661

'user123',

662

'activity_ddoc',

663

'activity_search',

664

q='login OR logout',

665

include_docs=True

666

)

667

```

668

669

### Result Collections Usage

670

671

```python

672

from cloudant import cloudant

673

from cloudant.result import Result, ResultByKey

674

675

with cloudant('user', 'pass', account='myaccount') as client:

676

db = client['my_database']

677

678

# Create result collection from view

679

result = Result(db.all_docs, include_docs=True)

680

681

# Index-based access

682

first_doc = result[0] # Skip 0, get 1st document

683

tenth_doc = result[9] # Skip 9, get 10th document

684

685

# Key-based access

686

specific_doc = result['doc_key_123'] # Get documents with key 'doc_key_123'

687

numeric_key = result[ResultByKey(42)] # Get documents with numeric key 42

688

689

# Slicing

690

first_ten = result[0:10] # First 10 documents

691

next_batch = result[10:20] # Documents 11-20

692

all_after_100 = result[100:] # All documents after 100th

693

key_range = result['aaa':'zzz'] # Documents with keys between 'aaa' and 'zzz'

694

695

# Iteration with automatic pagination

696

for doc in result:

697

print(f"Document: {doc['_id']}")

698

if doc.get('_id') == 'stop_here':

699

break

700

701

# Get all results at once

702

all_docs = result.all()

703

print(f"Total documents: {len(all_docs)}")

704

705

# Custom page size for iteration

706

large_result = Result(db.all_docs, page_size=1000, include_docs=True)

707

for doc in large_result:

708

process_document(doc)

709

```

710

711

### Query Result Collections

712

713

```python

714

from cloudant import cloudant

715

from cloudant.query import Query

716

from cloudant.result import QueryResult

717

718

with cloudant('user', 'pass', account='myaccount') as client:

719

db = client['my_database']

720

721

# Create query result collection

722

query = Query(db, selector={'type': 'user'})

723

query_result = QueryResult(query, page_size=50)

724

725

# Index-based access only (no key-based access for queries)

726

first_user = query_result[0]

727

users_10_to_20 = query_result[10:20]

728

729

# Iteration with bookmark pagination

730

for user in query_result:

731

print(f"User: {user['name']}")

732

733

# Custom query result with sort

734

sorted_result = QueryResult(

735

query,

736

sort=[{'created_date': 'desc'}],

737

fields=['_id', 'name', 'email']

738

)

739

740

recent_users = sorted_result[0:10] # 10 most recent users

741

```

742

743

### Advanced Result Patterns

744

745

```python

746

from cloudant import cloudant

747

from cloudant.result import Result, ResultByKey

748

749

with cloudant('user', 'pass', account='myaccount') as client:

750

db = client['my_database']

751

752

# Complex key access (for views with complex keys)

753

view_result = Result(db['_design/stats']['by_date_and_type'])

754

755

# Access by complex key

756

today_users = view_result[['2023-12-01', 'user']]

757

date_range = view_result[['2023-12-01']:['2023-12-31']]

758

759

# Numeric key handling

760

numeric_result = Result(db['_design/counters']['by_id'])

761

doc_by_id = numeric_result[ResultByKey(12345)] # Key access, not index

762

twelfth_doc = numeric_result[11] # Index access (12th document)

763

764

# Conditional iteration

765

filtered_result = Result(

766

db.all_docs,

767

startkey='prefix_',

768

endkey='prefix_\ufff0', # All keys starting with 'prefix_'

769

include_docs=True

770

)

771

772

for doc in filtered_result:

773

if doc['doc']['status'] == 'active':

774

print(f"Active document: {doc['id']}")

775

776

# Reduce view results

777

stats_result = Result(

778

db['_design/analytics']['monthly_stats'],

779

group=True,

780

group_level=2

781

)

782

783

for stat in stats_result:

784

month = stat['key']

785

value = stat['value']

786

print(f"Month {month}: {value} events")

787

```

788

789

### Query Performance Optimization

790

791

```python

792

from cloudant import cloudant

793

794

with cloudant('user', 'pass', account='myaccount') as client:

795

db = client['my_database']

796

797

# Force use of specific index

798

result = db.get_query_result(

799

selector={'type': 'user', 'status': 'active'},

800

use_index='user_status_idx',

801

execution_stats=True

802

)

803

804

# Check execution statistics

805

if hasattr(result, 'execution_stats'):

806

stats = result.execution_stats

807

print(f"Execution time: {stats.get('execution_time_ms')}ms")

808

print(f"Results examined: {stats.get('results_returned')}")

809

print(f"Documents examined: {stats.get('total_docs_examined')}")

810

print(f"Index used: {stats.get('index', {}).get('name')}")

811

812

# Query with hint for index selection

813

result = db.get_query_result(

814

selector={'category': 'electronics', 'price': {'$lt': 500}},

815

use_index=['category', 'price'], # Compound index

816

sort=[{'price': 'asc'}]

817

)

818

```

819

820

## Error Handling

821

822

Query and indexing operations can raise specific exceptions:

823

824

```python

825

from cloudant import cloudant

826

from cloudant.error import CloudantDatabaseException, CloudantIndexException

827

828

with cloudant('user', 'pass', account='myaccount') as client:

829

db = client['my_database']

830

831

try:

832

# Query with invalid selector

833

result = db.get_query_result({'invalid_operator': {'$invalid': 'value'}})

834

except CloudantDatabaseException as e:

835

print(f"Query failed: {e}")

836

837

try:

838

# Create duplicate index

839

db.create_query_index(fields=['email'], index_name='existing_index')

840

except CloudantIndexException as e:

841

print(f"Index creation failed: {e}")

842

843

try:

844

# Delete non-existent index

845

db.delete_query_index('_design/missing', 'json', 'missing_index')

846

except CloudantIndexException as e:

847

print(f"Index deletion failed: {e}")

848

```