Skip to main content

Read and write data

The BlockDB Python SDK wraps the three logical table types in corresponding classes: Table for regular tables, BlockTable for Block tables, and TimeTable for Time tables. Each class is a thin wrapper whose methods ultimately delegate to gRPC. Query methods return Python dict or list[dict]; write methods return a job_id.

The three table models and how to choose

Which model you choose depends on your data shape: regular tables for row-level data, Block tables for state and events that change with block height, Time tables for metrics that change with physical time. See Data model.

Regular tables (Table)

For row-level data, with primary-key reads/writes and full-table scans:
For large-table retrieval use scan_iter (streaming, row by row) and avoid list(scan_iter(...)), which would exhaust memory. The SQL you pass is executed as a stream and can handle result sets in the millions.

Block tables (BlockTable)

For block-oriented state and events, reading and writing with a block as the anchor:
get_state / get_event use current_block as the anchor and automatically inject height ≤ target height, returning the most recent snapshot at or below that height. The current block height must not exceed the table’s consensus height for the result to be correct — see Block State Table and Block Event Table.

Time tables (TimeTable)

For metrics that change with physical time, reading and writing by time bucket:
TimeTable performs the 60-second bucket alignment in the SDK: 17:04:35 aligns to 17:05:00, so reads and writes use the same convention. See Time Table.

Advanced writes

  • Conditional updates: upsert_rows on regular tables accepts condition=(column, "if_smaller"/"if_larger"), updating only when the new value is smaller/larger. Useful for monotonic values such as balances and heights:
  • Batch writes: backfilling millions of rows goes through the S3-staged batch write interfaces, which return a job_id you can query or cancel. See Write architecture.