or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-operations.mdcursors.mdindex.mdmulti-database.mdtransactions.md

cursors.mddocs/

0

# Cursor Operations and Iteration

1

2

Efficient database traversal and positioned access using cursors. Cursors provide powerful iteration capabilities, range queries, bulk operations, and precise positioning within the database's sorted key space.

3

4

## Capabilities

5

6

### Cursor Lifecycle

7

8

Create and manage cursor resources with proper cleanup and transaction binding.

9

10

```python { .api }

11

class Transaction:

12

def cursor(self, db=None) -> Cursor:

13

"""

14

Create cursor for database iteration.

15

16

Parameters:

17

- db: Database handle (uses transaction default if None)

18

19

Returns:

20

Cursor instance bound to transaction and database

21

"""

22

23

class Cursor:

24

def close(self) -> None:

25

"""

26

Close cursor and free resources.

27

Cursors are automatically closed when transaction ends.

28

"""

29

```

30

31

### Data Access

32

33

Access current cursor position data with key, value, and combined retrieval methods.

34

35

```python { .api }

36

class Cursor:

37

def key(self) -> bytes:

38

"""

39

Get key at current cursor position.

40

41

Returns:

42

Key bytes

43

44

Raises:

45

Error if cursor not positioned at valid record

46

"""

47

48

def value(self) -> bytes:

49

"""

50

Get value at current cursor position.

51

52

Returns:

53

Value bytes

54

55

Raises:

56

Error if cursor not positioned at valid record

57

"""

58

59

def item(self) -> tuple:

60

"""

61

Get (key, value) tuple at current cursor position.

62

63

Returns:

64

Tuple of (key_bytes, value_bytes)

65

66

Raises:

67

Error if cursor not positioned at valid record

68

"""

69

70

def get(self, key: bytes, default=None) -> bytes:

71

"""

72

Get value for specified key using cursor.

73

74

Parameters:

75

- key: Key to lookup

76

- default: Value returned if key not found

77

78

Returns:

79

Value bytes or default if key not found

80

"""

81

82

def count(self) -> int:

83

"""

84

Count duplicate values for current key.

85

86

Returns:

87

Number of duplicates for current key

88

89

Note:

90

Only meaningful for databases opened with dupsort=True

91

"""

92

```

93

94

### Positioning and Navigation

95

96

Navigate through database records with precise positioning and movement operations.

97

98

```python { .api }

99

class Cursor:

100

def first(self) -> bool:

101

"""

102

Position cursor at first record in database.

103

104

Returns:

105

True if record found, False if database empty

106

"""

107

108

def last(self) -> bool:

109

"""

110

Position cursor at last record in database.

111

112

Returns:

113

True if record found, False if database empty

114

"""

115

116

def next(self) -> bool:

117

"""

118

Move cursor to next record.

119

120

Returns:

121

True if moved to valid record, False if at end

122

"""

123

124

def prev(self) -> bool:

125

"""

126

Move cursor to previous record.

127

128

Returns:

129

True if moved to valid record, False if at beginning

130

"""

131

132

def set_key(self, key: bytes) -> bool:

133

"""

134

Position cursor at specified key.

135

136

Parameters:

137

- key: Key to locate

138

139

Returns:

140

True if exact key found, False otherwise

141

"""

142

143

def set_range(self, key: bytes) -> bool:

144

"""

145

Position cursor at first key >= specified key.

146

147

Parameters:

148

- key: Minimum key value

149

150

Returns:

151

True if positioned at valid record, False if no keys >= key

152

"""

153

```

154

155

### Duplicate Key Navigation

156

157

Navigate through duplicate values for databases configured with dupsort=True.

158

159

```python { .api }

160

class Cursor:

161

def first_dup(self) -> bool:

162

"""

163

Position at first duplicate of current key.

164

165

Returns:

166

True if positioned, False if no duplicates or not positioned

167

"""

168

169

def last_dup(self) -> bool:

170

"""

171

Position at last duplicate of current key.

172

173

Returns:

174

True if positioned, False if no duplicates or not positioned

175

"""

176

177

def next_dup(self) -> bool:

178

"""

179

Move to next duplicate of current key.

180

181

Returns:

182

True if moved to duplicate, False if no more duplicates

183

"""

184

185

def prev_dup(self) -> bool:

186

"""

187

Move to previous duplicate of current key.

188

189

Returns:

190

True if moved to duplicate, False if no previous duplicates

191

"""

192

193

def next_nodup(self) -> bool:

194

"""

195

Move to next key (skipping any remaining duplicates of current key).

196

197

Returns:

198

True if moved to different key, False if at end

199

"""

200

201

def prev_nodup(self) -> bool:

202

"""

203

Move to previous key (skipping any remaining duplicates of current key).

204

205

Returns:

206

True if moved to different key, False if at beginning

207

"""

208

209

def set_key_dup(self, key: bytes, value: bytes) -> bool:

210

"""

211

Position at specific key-value pair.

212

213

Parameters:

214

- key: Key to locate

215

- value: Specific value for the key

216

217

Returns:

218

True if exact key-value pair found

219

"""

220

221

def set_range_dup(self, key: bytes, value: bytes) -> bool:

222

"""

223

Position at first occurrence of key with value >= specified value.

224

225

Parameters:

226

- key: Key to locate

227

- value: Minimum value for the key

228

229

Returns:

230

True if positioned at valid record

231

"""

232

```

233

234

### Data Modification

235

236

Modify database through cursor with positioned insert, update, and delete operations.

237

238

```python { .api }

239

class Cursor:

240

def put(self, key: bytes, value: bytes, dupdata: bool = True,

241

overwrite: bool = True, append: bool = False) -> bool:

242

"""

243

Store key-value pair at cursor position.

244

245

Parameters:

246

- key: Key bytes

247

- value: Value bytes

248

- dupdata: Allow duplicate keys

249

- overwrite: Replace existing value

250

- append: Optimize for appending (key must be >= all existing keys)

251

252

Returns:

253

True if new key inserted, False if existing key updated

254

"""

255

256

def delete(self, dupdata: bool = True) -> bool:

257

"""

258

Delete record at current cursor position.

259

260

Parameters:

261

- dupdata: Delete only current duplicate (False deletes all duplicates)

262

263

Returns:

264

True if record deleted

265

"""

266

267

def replace(self, key: bytes, value: bytes) -> bytes:

268

"""

269

Replace value at cursor position and return old value.

270

271

Parameters:

272

- key: Key (must match current position)

273

- value: New value

274

275

Returns:

276

Previous value

277

"""

278

279

def pop(self, dupdata: bool = True) -> tuple:

280

"""

281

Get current record and delete it.

282

283

Parameters:

284

- dupdata: Delete only current duplicate

285

286

Returns:

287

Tuple of (key, value) that was deleted

288

"""

289

```

290

291

### Iterator Interface

292

293

Python iterator protocol support for convenient record traversal with flexible options.

294

295

```python { .api }

296

class Cursor:

297

def iternext(self, keys: bool = True, values: bool = True) -> Iterator:

298

"""

299

Forward iterator from current position.

300

301

Parameters:

302

- keys: Include keys in iteration

303

- values: Include values in iteration

304

305

Yields:

306

Keys, values, or (key, value) tuples based on parameters

307

"""

308

309

def iternext_dup(self, keys: bool = True, values: bool = True) -> Iterator:

310

"""

311

Forward iterator over duplicates of current key.

312

313

Parameters:

314

- keys: Include keys in iteration

315

- values: Include values in iteration

316

317

Yields:

318

Records for current key only

319

"""

320

321

def iternext_nodup(self, keys: bool = True, values: bool = True) -> Iterator:

322

"""

323

Forward iterator skipping duplicate keys.

324

325

Parameters:

326

- keys: Include keys in iteration

327

- values: Include values in iteration

328

329

Yields:

330

First record for each unique key

331

"""

332

333

def iterprev(self, keys: bool = True, values: bool = True) -> Iterator:

334

"""

335

Reverse iterator from current position.

336

337

Parameters:

338

- keys: Include keys in iteration

339

- values: Include values in iteration

340

341

Yields:

342

Keys, values, or (key, value) tuples in reverse order

343

"""

344

345

def iterprev_dup(self, keys: bool = True, values: bool = True) -> Iterator:

346

"""

347

Reverse iterator over duplicates of current key.

348

349

Parameters:

350

- keys: Include keys in iteration

351

- values: Include values in iteration

352

353

Yields:

354

Records for current key in reverse order

355

"""

356

357

def iterprev_nodup(self, keys: bool = True, values: bool = True) -> Iterator:

358

"""

359

Reverse iterator skipping duplicate keys.

360

361

Parameters:

362

- keys: Include keys in iteration

363

- values: Include values in iteration

364

365

Yields:

366

Last record for each unique key in reverse order

367

"""

368

```

369

370

### Bulk Operations

371

372

Efficient batch operations for high-performance data processing.

373

374

```python { .api }

375

class Cursor:

376

def putmulti(self, items: Iterable, dupdata: bool = True,

377

overwrite: bool = True, append: bool = False) -> int:

378

"""

379

Store multiple key-value pairs efficiently.

380

381

Parameters:

382

- items: Iterable of (key, value) tuples

383

- dupdata: Allow duplicate keys

384

- overwrite: Replace existing values

385

- append: Optimize for sequential insertion

386

387

Returns:

388

Number of items successfully stored

389

"""

390

391

def getmulti(self, keys: Iterable, dupdata: bool = False) -> list:

392

"""

393

Retrieve multiple values by keys efficiently.

394

395

Parameters:

396

- keys: Iterable of key bytes

397

- dupdata: Retrieve all duplicates for each key

398

399

Returns:

400

List of (key, value) tuples for found keys

401

"""

402

```

403

404

### Usage Examples

405

406

#### Basic Cursor Iteration

407

408

```python

409

import lmdb

410

411

env = lmdb.open('/path/to/database')

412

413

# Forward iteration over all records

414

with env.begin() as txn:

415

cursor = txn.cursor()

416

417

# Iterate using cursor as iterator

418

for key, value in cursor:

419

print(f"Key: {key}, Value: {value}")

420

421

# Or iterate manually

422

if cursor.first():

423

print(f"First: {cursor.key()} = {cursor.value()}")

424

425

while cursor.next():

426

print(f"Next: {cursor.key()} = {cursor.value()}")

427

428

env.close()

429

```

430

431

#### Range Queries

432

433

```python

434

import lmdb

435

436

env = lmdb.open('/path/to/database')

437

438

with env.begin() as txn:

439

cursor = txn.cursor()

440

441

# Find all keys starting with 'user:'

442

start_key = b'user:'

443

end_key = b'user;' # ';' is next ASCII character after ':'

444

445

# Position at first key >= start_key

446

if cursor.set_range(start_key):

447

while cursor.key() < end_key:

448

key, value = cursor.item()

449

print(f"User record: {key} = {value}")

450

451

if not cursor.next():

452

break

453

454

# Range query with specific bounds

455

print("\\nUsers 100-199:")

456

if cursor.set_range(b'user:100'):

457

while cursor.key().startswith(b'user:1'):

458

key, value = cursor.item()

459

user_id = key[5:] # Remove 'user:' prefix

460

if user_id > b'199':

461

break

462

print(f"User {user_id}: {value}")

463

464

if not cursor.next():

465

break

466

467

env.close()

468

```

469

470

#### Working with Duplicates

471

472

```python

473

import lmdb

474

475

# Open environment with duplicate support

476

env = lmdb.open('/path/to/database', max_dbs=1)

477

tags_db = env.open_db(b'post_tags', dupsort=True)

478

479

# Store posts with multiple tags

480

with env.begin(write=True) as txn:

481

cursor = txn.cursor(db=tags_db)

482

483

# Post 1 has multiple tags

484

cursor.put(b'post:1', b'python')

485

cursor.put(b'post:1', b'database')

486

cursor.put(b'post:1', b'tutorial')

487

488

# Post 2 has different tags

489

cursor.put(b'post:2', b'javascript')

490

cursor.put(b'post:2', b'web')

491

492

# Read all tags for a specific post

493

with env.begin() as txn:

494

cursor = txn.cursor(db=tags_db)

495

496

# Find all tags for post:1

497

if cursor.set_key(b'post:1'):

498

print(f"Tags for post:1:")

499

print(f" {cursor.value()}") # First tag

500

501

# Get remaining tags for same post

502

while cursor.next_dup():

503

print(f" {cursor.value()}")

504

505

# Iterate through all posts and their tags

506

print("\\nAll posts and tags:")

507

cursor.first()

508

current_post = None

509

510

for key, value in cursor:

511

if key != current_post:

512

current_post = key

513

print(f"\\n{key}:")

514

print(f" {value}")

515

516

env.close()

517

```

518

519

#### Bulk Operations

520

521

```python

522

import lmdb

523

524

env = lmdb.open('/path/to/database')

525

526

# Bulk insert

527

with env.begin(write=True) as txn:

528

cursor = txn.cursor()

529

530

# Prepare large dataset

531

items = [(f'key{i:06d}'.encode(), f'value{i}'.encode())

532

for i in range(10000)]

533

534

# Efficient bulk insert

535

count = cursor.putmulti(items, append=True) # append=True for sequential keys

536

print(f"Inserted {count} items")

537

538

# Bulk retrieval

539

with env.begin() as txn:

540

cursor = txn.cursor()

541

542

# Get specific keys

543

keys_to_fetch = [f'key{i:06d}'.encode() for i in range(0, 1000, 100)]

544

results = cursor.getmulti(keys_to_fetch)

545

546

print(f"Retrieved {len(results)} items:")

547

for key, value in results[:5]: # Show first 5

548

print(f" {key} = {value}")

549

550

env.close()

551

```

552

553

#### Reverse Iteration

554

555

```python

556

import lmdb

557

558

env = lmdb.open('/path/to/database')

559

560

with env.begin() as txn:

561

cursor = txn.cursor()

562

563

# Start from last record and work backwards

564

if cursor.last():

565

print("Reverse iteration:")

566

print(f"Last: {cursor.key()} = {cursor.value()}")

567

568

while cursor.prev():

569

print(f"Prev: {cursor.key()} = {cursor.value()}")

570

571

# Use reverse iterator

572

print("\\nUsing reverse iterator:")

573

cursor.last()

574

for key, value in cursor.iterprev():

575

print(f"{key} = {value}")

576

577

env.close()

578

```