Skip to content

Reading Records

This guide covers all methods for retrieving records from Teable tables.

Getting Records

Basic Record Retrieval

from teable import TeableClient, TeableConfig

# Initialize client
client = TeableClient(TeableConfig(api_key="your_api_key"))

# Get records with default parameters
records = client.records.get_records(
    table_id="table_id",
    field_key_type="name"  # Use field names instead of IDs
)

Advanced Query Parameters

# Get records with all available parameters
records = client.records.get_records(
    table_id="table_id",
    projection=["Name", "Email"],  # Only return specific fields
    cell_format="json",  # 'json' or 'text'
    field_key_type="name",  # 'name' or 'id'
    view_id="view_id",  # Filter by view
    ignore_view_query=False,  # Whether to ignore view's filter/sort
    filter_by_tql="Name = 'John'",  # Filter using Teable Query Language
    filter={  # Complex filter object
        "filterSet": [
            {
                "fieldId": "Age",
                "operator": "isGreaterEqual",
                "value": 30
            }
        ],
        "conjunction": "and"
    },
    search=[  # Search parameters
        {
            "value": "John",
            "field": "Name",
            "exact": True
        }
    ],
    filter_link_cell_candidate="linked_record_id",  # Filter by link field candidates
    filter_link_cell_selected="selected_record_id",  # Filter by link field selection
    selected_record_ids=["record1", "record2"],  # Filter by specific records
    order_by="Name",  # Sort specification
    group_by="Department",  # Group specification
    collapsed_group_ids=["group1", "group2"],  # List of collapsed group IDs
    take=100,  # Number of records to return (max 2000)
    skip=0  # Number of records to skip
)

Getting a Single Record

# Get a single record by ID
record = client.records.get_record(
    table_id="table_id",
    record_id="record_id",
    projection=["Name", "Email"],  # Optional: specific fields
    cell_format="json",  # Optional: format
    field_key_type="name"  # Optional: key type
)

Record Status and History

Checking Record Status

# Get record visibility and deletion status
status = client.records.get_record_status(
    table_id="table_id",
    record_id="record_id"
)

print(f"Is visible: {status.is_visible}")
print(f"Is deleted: {status.is_deleted}")

Getting Record History

# Get history for a specific record
history = client.records.get_record_history(
    table_id="table_id",
    record_id="record_id"
)

# Print history entries
for entry in history.entries:
    print(f"Changed by: {history.users[entry.user_id].name}")
    print(f"Action: {entry.action}")
    print(f"Time: {entry.created_time}")

# Get history for all records in a table
table_history = client.records.get_table_record_history(
    table_id="table_id"
)

Search and Filter Options

# Simple text search
records = client.records.get_records(
    table_id="table_id",
    search=[{
        "value": "John",
        "field": "Name",
        "exact": True  # Exact match
    }]
)

# Multiple search criteria
records = client.records.get_records(
    table_id="table_id",
    search=[
        {
            "value": "John",
            "field": "Name",
            "exact": False  # Partial match
        },
        {
            "value": "Developer",
            "field": "Title",
            "exact": True
        }
    ]
)

Complex Filtering

# Filter with multiple conditions
records = client.records.get_records(
    table_id="table_id",
    filter={
        "filterSet": [
            {
                "fieldId": "Age",
                "operator": "isGreaterEqual",
                "value": 30
            },
            {
                "fieldId": "Department",
                "operator": "is",
                "value": "Engineering"
            }
        ],
        "conjunction": "and"
    }
)

# Filter with TQL (Teable Query Language)
records = client.records.get_records(
    table_id="table_id",
    filter_by_tql="Age >= 30 AND Department = 'Engineering'"
)

Pagination

def fetch_all_records(client, table_id):
    """Fetch all records using pagination."""
    all_records = []
    page_size = 100
    skip = 0

    while True:
        records = client.records.get_records(
            table_id=table_id,
            take=page_size,
            skip=skip
        )

        if not records:
            break

        all_records.extend(records)
        skip += page_size

        if len(records) < page_size:
            break

    return all_records

Error Handling

from teable.exceptions import ValidationError, APIError

try:
    records = client.records.get_records(
        table_id="table_id",
        take=3000  # Exceeds maximum
    )
except ValidationError as e:
    print(f"Validation error: {str(e)}")
except APIError as e:
    print(f"API error: {str(e)}")
    print(f"Status code: {e.status_code}")
    print(f"Error details: {e.details}")

Best Practices

1. Use Field Projections

# DON'T: Fetch all fields when not needed
records = client.records.get_records(table_id="table_id")

# DO: Only fetch required fields
records = client.records.get_records(
    table_id="table_id",
    projection=["Name", "Email"]  # Only fetch needed fields
)

2. Implement Pagination

# DON'T: Fetch all records at once
records = client.records.get_records(table_id="table_id")

# DO: Use pagination
def process_records_in_batches(client, table_id, batch_size=100):
    skip = 0
    while True:
        batch = client.records.get_records(
            table_id=table_id,
            take=batch_size,
            skip=skip
        )

        if not batch:
            break

        process_batch(batch)
        skip += batch_size

3. Use Efficient Filtering

# DON'T: Filter in memory
records = client.records.get_records(table_id="table_id")
filtered = [r for r in records if r["Age"] > 30]  # Inefficient

# DO: Filter at API level
records = client.records.get_records(
    table_id="table_id",
    filter={
        "filterSet": [
            {
                "fieldId": "Age",
                "operator": "isGreaterThan",
                "value": 30
            }
        ]
    }
)

4. Handle Rate Limits

import time
from teable.exceptions import APIError

def get_records_with_retry(client, table_id, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.records.get_records(table_id=table_id)
        except APIError as e:
            if e.status_code == 429:  # Rate limit
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)  # Exponential backoff
                    continue
            raise
    raise Exception("Max retries exceeded")

5. Cache Results When Appropriate

```python from functools import lru_cache from datetime import datetime, timedelta

@lru_cache(maxsize=100) def get_cached_record(client, table_id, record_id): """Cache individual record lookups.""" return client.records.get_record( table_id=table_id, record_id=record_id )

class RecordCache: """Time-based cache for record queries.""" def init(self, ttl_seconds=300): self.cache = {} self.ttl = timedelta(seconds=ttl_seconds)

def get_records(self, client, table_id, **query_params):
    cache_key = f"{table_id}:{str(query_params)}"
    now = datetime.now()

    if cache_key in self.cache:
        result, timestamp = self.cache[cache_key]
        if now - timestamp < self.ttl:
            return result

    result = client.records.get_records(
        table_id=table_id,
        **query_params
    )
    self.cache[cache_key] = (result, now)
    return result