Universal Python binding for the LMDB 'Lightning' Database
—
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.
Create and manage cursor resources with proper cleanup and transaction binding.
class Transaction:
def cursor(self, db=None) -> Cursor:
"""
Create cursor for database iteration.
Parameters:
- db: Database handle (uses transaction default if None)
Returns:
Cursor instance bound to transaction and database
"""
class Cursor:
def close(self) -> None:
"""
Close cursor and free resources.
Cursors are automatically closed when transaction ends.
"""Access current cursor position data with key, value, and combined retrieval methods.
class Cursor:
def key(self) -> bytes:
"""
Get key at current cursor position.
Returns:
Key bytes
Raises:
Error if cursor not positioned at valid record
"""
def value(self) -> bytes:
"""
Get value at current cursor position.
Returns:
Value bytes
Raises:
Error if cursor not positioned at valid record
"""
def item(self) -> tuple:
"""
Get (key, value) tuple at current cursor position.
Returns:
Tuple of (key_bytes, value_bytes)
Raises:
Error if cursor not positioned at valid record
"""
def get(self, key: bytes, default=None) -> bytes:
"""
Get value for specified key using cursor.
Parameters:
- key: Key to lookup
- default: Value returned if key not found
Returns:
Value bytes or default if key not found
"""
def count(self) -> int:
"""
Count duplicate values for current key.
Returns:
Number of duplicates for current key
Note:
Only meaningful for databases opened with dupsort=True
"""Navigate through database records with precise positioning and movement operations.
class Cursor:
def first(self) -> bool:
"""
Position cursor at first record in database.
Returns:
True if record found, False if database empty
"""
def last(self) -> bool:
"""
Position cursor at last record in database.
Returns:
True if record found, False if database empty
"""
def next(self) -> bool:
"""
Move cursor to next record.
Returns:
True if moved to valid record, False if at end
"""
def prev(self) -> bool:
"""
Move cursor to previous record.
Returns:
True if moved to valid record, False if at beginning
"""
def set_key(self, key: bytes) -> bool:
"""
Position cursor at specified key.
Parameters:
- key: Key to locate
Returns:
True if exact key found, False otherwise
"""
def set_range(self, key: bytes) -> bool:
"""
Position cursor at first key >= specified key.
Parameters:
- key: Minimum key value
Returns:
True if positioned at valid record, False if no keys >= key
"""Navigate through duplicate values for databases configured with dupsort=True.
class Cursor:
def first_dup(self) -> bool:
"""
Position at first duplicate of current key.
Returns:
True if positioned, False if no duplicates or not positioned
"""
def last_dup(self) -> bool:
"""
Position at last duplicate of current key.
Returns:
True if positioned, False if no duplicates or not positioned
"""
def next_dup(self) -> bool:
"""
Move to next duplicate of current key.
Returns:
True if moved to duplicate, False if no more duplicates
"""
def prev_dup(self) -> bool:
"""
Move to previous duplicate of current key.
Returns:
True if moved to duplicate, False if no previous duplicates
"""
def next_nodup(self) -> bool:
"""
Move to next key (skipping any remaining duplicates of current key).
Returns:
True if moved to different key, False if at end
"""
def prev_nodup(self) -> bool:
"""
Move to previous key (skipping any remaining duplicates of current key).
Returns:
True if moved to different key, False if at beginning
"""
def set_key_dup(self, key: bytes, value: bytes) -> bool:
"""
Position at specific key-value pair.
Parameters:
- key: Key to locate
- value: Specific value for the key
Returns:
True if exact key-value pair found
"""
def set_range_dup(self, key: bytes, value: bytes) -> bool:
"""
Position at first occurrence of key with value >= specified value.
Parameters:
- key: Key to locate
- value: Minimum value for the key
Returns:
True if positioned at valid record
"""Modify database through cursor with positioned insert, update, and delete operations.
class Cursor:
def put(self, key: bytes, value: bytes, dupdata: bool = True,
overwrite: bool = True, append: bool = False) -> bool:
"""
Store key-value pair at cursor position.
Parameters:
- key: Key bytes
- value: Value bytes
- dupdata: Allow duplicate keys
- overwrite: Replace existing value
- append: Optimize for appending (key must be >= all existing keys)
Returns:
True if new key inserted, False if existing key updated
"""
def delete(self, dupdata: bool = True) -> bool:
"""
Delete record at current cursor position.
Parameters:
- dupdata: Delete only current duplicate (False deletes all duplicates)
Returns:
True if record deleted
"""
def replace(self, key: bytes, value: bytes) -> bytes:
"""
Replace value at cursor position and return old value.
Parameters:
- key: Key (must match current position)
- value: New value
Returns:
Previous value
"""
def pop(self, dupdata: bool = True) -> tuple:
"""
Get current record and delete it.
Parameters:
- dupdata: Delete only current duplicate
Returns:
Tuple of (key, value) that was deleted
"""Python iterator protocol support for convenient record traversal with flexible options.
class Cursor:
def iternext(self, keys: bool = True, values: bool = True) -> Iterator:
"""
Forward iterator from current position.
Parameters:
- keys: Include keys in iteration
- values: Include values in iteration
Yields:
Keys, values, or (key, value) tuples based on parameters
"""
def iternext_dup(self, keys: bool = True, values: bool = True) -> Iterator:
"""
Forward iterator over duplicates of current key.
Parameters:
- keys: Include keys in iteration
- values: Include values in iteration
Yields:
Records for current key only
"""
def iternext_nodup(self, keys: bool = True, values: bool = True) -> Iterator:
"""
Forward iterator skipping duplicate keys.
Parameters:
- keys: Include keys in iteration
- values: Include values in iteration
Yields:
First record for each unique key
"""
def iterprev(self, keys: bool = True, values: bool = True) -> Iterator:
"""
Reverse iterator from current position.
Parameters:
- keys: Include keys in iteration
- values: Include values in iteration
Yields:
Keys, values, or (key, value) tuples in reverse order
"""
def iterprev_dup(self, keys: bool = True, values: bool = True) -> Iterator:
"""
Reverse iterator over duplicates of current key.
Parameters:
- keys: Include keys in iteration
- values: Include values in iteration
Yields:
Records for current key in reverse order
"""
def iterprev_nodup(self, keys: bool = True, values: bool = True) -> Iterator:
"""
Reverse iterator skipping duplicate keys.
Parameters:
- keys: Include keys in iteration
- values: Include values in iteration
Yields:
Last record for each unique key in reverse order
"""Efficient batch operations for high-performance data processing.
class Cursor:
def putmulti(self, items: Iterable, dupdata: bool = True,
overwrite: bool = True, append: bool = False) -> int:
"""
Store multiple key-value pairs efficiently.
Parameters:
- items: Iterable of (key, value) tuples
- dupdata: Allow duplicate keys
- overwrite: Replace existing values
- append: Optimize for sequential insertion
Returns:
Number of items successfully stored
"""
def getmulti(self, keys: Iterable, dupdata: bool = False) -> list:
"""
Retrieve multiple values by keys efficiently.
Parameters:
- keys: Iterable of key bytes
- dupdata: Retrieve all duplicates for each key
Returns:
List of (key, value) tuples for found keys
"""import lmdb
env = lmdb.open('/path/to/database')
# Forward iteration over all records
with env.begin() as txn:
cursor = txn.cursor()
# Iterate using cursor as iterator
for key, value in cursor:
print(f"Key: {key}, Value: {value}")
# Or iterate manually
if cursor.first():
print(f"First: {cursor.key()} = {cursor.value()}")
while cursor.next():
print(f"Next: {cursor.key()} = {cursor.value()}")
env.close()import lmdb
env = lmdb.open('/path/to/database')
with env.begin() as txn:
cursor = txn.cursor()
# Find all keys starting with 'user:'
start_key = b'user:'
end_key = b'user;' # ';' is next ASCII character after ':'
# Position at first key >= start_key
if cursor.set_range(start_key):
while cursor.key() < end_key:
key, value = cursor.item()
print(f"User record: {key} = {value}")
if not cursor.next():
break
# Range query with specific bounds
print("\\nUsers 100-199:")
if cursor.set_range(b'user:100'):
while cursor.key().startswith(b'user:1'):
key, value = cursor.item()
user_id = key[5:] # Remove 'user:' prefix
if user_id > b'199':
break
print(f"User {user_id}: {value}")
if not cursor.next():
break
env.close()import lmdb
# Open environment with duplicate support
env = lmdb.open('/path/to/database', max_dbs=1)
tags_db = env.open_db(b'post_tags', dupsort=True)
# Store posts with multiple tags
with env.begin(write=True) as txn:
cursor = txn.cursor(db=tags_db)
# Post 1 has multiple tags
cursor.put(b'post:1', b'python')
cursor.put(b'post:1', b'database')
cursor.put(b'post:1', b'tutorial')
# Post 2 has different tags
cursor.put(b'post:2', b'javascript')
cursor.put(b'post:2', b'web')
# Read all tags for a specific post
with env.begin() as txn:
cursor = txn.cursor(db=tags_db)
# Find all tags for post:1
if cursor.set_key(b'post:1'):
print(f"Tags for post:1:")
print(f" {cursor.value()}") # First tag
# Get remaining tags for same post
while cursor.next_dup():
print(f" {cursor.value()}")
# Iterate through all posts and their tags
print("\\nAll posts and tags:")
cursor.first()
current_post = None
for key, value in cursor:
if key != current_post:
current_post = key
print(f"\\n{key}:")
print(f" {value}")
env.close()import lmdb
env = lmdb.open('/path/to/database')
# Bulk insert
with env.begin(write=True) as txn:
cursor = txn.cursor()
# Prepare large dataset
items = [(f'key{i:06d}'.encode(), f'value{i}'.encode())
for i in range(10000)]
# Efficient bulk insert
count = cursor.putmulti(items, append=True) # append=True for sequential keys
print(f"Inserted {count} items")
# Bulk retrieval
with env.begin() as txn:
cursor = txn.cursor()
# Get specific keys
keys_to_fetch = [f'key{i:06d}'.encode() for i in range(0, 1000, 100)]
results = cursor.getmulti(keys_to_fetch)
print(f"Retrieved {len(results)} items:")
for key, value in results[:5]: # Show first 5
print(f" {key} = {value}")
env.close()import lmdb
env = lmdb.open('/path/to/database')
with env.begin() as txn:
cursor = txn.cursor()
# Start from last record and work backwards
if cursor.last():
print("Reverse iteration:")
print(f"Last: {cursor.key()} = {cursor.value()}")
while cursor.prev():
print(f"Prev: {cursor.key()} = {cursor.value()}")
# Use reverse iterator
print("\\nUsing reverse iterator:")
cursor.last()
for key, value in cursor.iterprev():
print(f"{key} = {value}")
env.close()Install with Tessl CLI
npx tessl i tessl/pypi-lmdb