
Chdb Datastore
- 5.7k installs
- 510 repo stars
- Updated August 2, 2026
- clickhouse/agent-skills
chdb-datastore is an agent skill that apply chdb-datastore agent skill workflows from documented skill.md guidance.
About
chdb-datastore is an agent skill from clickhouse/agent-skills that apply chdb-datastore agent skill workflows from documented skill.md guidance. # chdb DataStore — It's Just Faster Pandas ## The Key Insight ```python # Change this: import pandas as pd # To this: import chdb.datastore as pd # Everything else stays the same. ``` DataStore is a **lazy, ClickHouse-backed pandas replacement**. Your existing pandas code works unchanged — but operations compile to optimized SQL and execute only Developers invoke chdb-datastore during build/integrations work for backend & apis tasks. The skill documents triggers, prerequisites, and step-by-step workflows grounded in SKILL.md. Compatible with Claude Code, Cursor, and Codex agent runtimes that load marketplace skills. Review the Security Audits panel on this listing before installing in production environments. Category Backend & APIs with development vertical focus supports repeatable agent-guided delivery.
- chdb DataStore — It's Just Faster Pandas
- import chdb.datastore as pd
- Everything else stays the same.
- Decision Tree: Pick the Right Approach
- 1. "I have a file/database and want to analyze it with pandas"
Chdb Datastore by the numbers
- 5,671 all-time installs (skills.sh)
- +980 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #130 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
chdb-datastore capabilities & compatibility
- Capabilities
- chdb datastore — it's just faster pandas · import chdb.datastore as pd · everything else stays the same. · decision tree: pick the right approach · 1. "i have a file/database and want to analyze i
- Use cases
- orchestration
What chdb-datastore says it does
1. "I have a file/database and want to analyze it with pandas"
→ DataStore.from_file() / from_mysql() / from_s3() etc.
2. "I need to join data from different sources"
npx skills add https://github.com/clickhouse/agent-skills --skill chdb-datastoreAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5.7k |
|---|---|
| repo stars | ★ 510 |
| Security audit | 2 / 3 scanners passed |
| Last updated | August 2, 2026 |
| Repository | clickhouse/agent-skills ↗ |
What it does
Apply chdb-datastore agent skill workflows from documented SKILL.md guidance.
Who is it for?
Developers working on backend & apis during build tasks.
Skip if: Tasks outside Backend & APIs scope described in SKILL.md.
When should I use this skill?
Apply chdb-datastore agent skill workflows from documented SKILL.md guidance.
What you get
Completed backend & apis workflow aligned with SKILL.md steps.
- Lazy DataFrame query pipelines
- Cross-source join results
- Generated SQL from to_sql()
By the numbers
- 209 DataFrame methods supported in the DataStore API
- 16+ data source connectors including S3, MySQL, PostgreSQL, Iceberg, Delta, and Hudi
- 10+ runnable examples bundled in examples/examples.md
Files
chdb DataStore — It's Just Faster Pandas
The Key Insight
# Change this:
import pandas as pd
# To this:
import chdb.datastore as pd
# Everything else stays the same.DataStore is a lazy, ClickHouse-backed pandas replacement. Your existing pandas code works unchanged — but operations compile to optimized SQL and execute only when results are needed (e.g., print(), len(), iteration).
pip install chdbDecision Tree: Pick the Right Approach
1. "I have a file/database and want to analyze it with pandas"
→ DataStore.from_file() / from_mysql() / from_s3() etc.
→ See references/connectors.md
2. "I need to join data from different sources"
→ Create DataStores from each source, use .join()
→ See examples/examples.md #3-5
3. "My pandas code is too slow"
→ import chdb.datastore as pd — change one line, keep the rest
4. "I need raw SQL queries"
→ Use the chdb-sql skill insteadConnect to Any Data Source — One Pattern
from datastore import DataStore
# Local file (auto-detects .parquet, .csv, .json, .arrow, .orc, .avro, .tsv, .xml)
ds = DataStore.from_file("sales.parquet")
# Database
ds = DataStore.from_mysql(host="db:3306", database="shop", table="orders", user="root", password="pass")
# Cloud storage
ds = DataStore.from_s3("s3://bucket/data.parquet", nosign=True)
# URI shorthand — auto-detects source type
ds = DataStore.uri("mysql://root:pass@db:3306/shop/orders")All 16+ sources and URI schemes → connectors.md
After Connecting — Full Pandas API
result = ds[ds["age"] > 25] # filter
result = ds[["name", "city"]] # select columns
result = ds.sort_values("revenue", ascending=False) # sort
result = ds.groupby("dept")["salary"].mean() # groupby
result = ds.assign(margin=lambda x: x["profit"] / x["revenue"]) # computed column
ds["name"].str.upper() # string accessor
ds["date"].dt.year # datetime accessor
result = ds1.join(ds2, on="id") # join
result = ds.head(10) # preview
print(ds.to_sql()) # see generated SQL209 DataFrame methods supported. Full API → api-reference.md
Cross-Source Join — The Killer Feature
from datastore import DataStore
customers = DataStore.from_mysql(host="db:3306", database="crm", table="customers", user="root", password="pass")
orders = DataStore.from_file("orders.parquet")
result = (orders
.join(customers, left_on="customer_id", right_on="id")
.groupby("country")
.agg({"amount": "sum", "rating": "mean"})
.sort_values("sum", ascending=False))
print(result)More join examples → examples.md
Writing Data
source = DataStore.from_mysql(host="db:3306", database="shop", table="orders", user="root", password="pass")
target = DataStore("file", path="summary.parquet", format="Parquet")
target.insert_into("category", "total", "count").select_from(
source.groupby("category").select("category", "sum(amount) AS total", "count() AS count")
).execute()Troubleshooting
| Problem | Fix |
|---|---|
ImportError: No module named 'chdb' | pip install chdb |
ImportError: cannot import 'DataStore' | Use from datastore import DataStore or from chdb.datastore import DataStore |
| Database connection timeout | Include port in host: host="db:3306" not host="db" |
| Join returns empty result | Check key types match (both int or both string); use .to_sql() to inspect |
| Unexpected results | Call ds.to_sql() to see the generated SQL and debug |
| Environment check | Run python scripts/verify_install.py (from skill directory) |
References
- API Reference — Full DataStore method signatures
- Connectors — All 16+ data source connection methods
- Examples — 10+ runnable examples with expected output
- Verify Install — Environment verification script
- Official Docs
Note: This skill teaches how to use chdb DataStore.
For raw SQL queries, use the chdb-sql skill.For contributing to chdb source code, see CLAUDE.md in the project root.
DataStore Examples
All examples are self-contained and runnable.
Expected output is shown in comments.
Table of Contents
1. Pandas Replacement: One Import Change 2. Analyze Local Files 3. Cross-Source Join: MySQL + Parquet 4. Cross-Source Join: S3 + PostgreSQL 5. Three-Way Join: File + Database + Cloud 6. Data Lake Formats: Iceberg, Delta, Hudi 7. URI Shorthand Access 8. Cloud Storage Variants (S3/GCS/Azure/HDFS) 9. Cross-Source Write 10. Explore Remote Schema 11. Common Errors & Fixes
---
1. Pandas Replacement: One Import Change
The simplest way to use chdb — change one line, keep everything else:
# Before (standard pandas):
# import pandas as pd
# After (chdb-accelerated):
import chdb.datastore as pd
df = pd.DataStore({"name": ["Alice", "Bob", "Carol", "Dave"],
"dept": ["Eng", "Sales", "Eng", "Sales"],
"salary": [95000, 72000, 110000, 68000]})
# Same pandas API — everything works
result = (df[df["salary"] > 70000]
.groupby("dept")
.agg({"salary": ["mean", "count"]})
.sort_values("mean", ascending=False))
print(result)
# Expected output:
# dept mean count
# 0 Eng 102500 2
# 1 Sales 72000 1Why it's faster: Operations compile to ClickHouse SQL and execute as a single optimized query, instead of step-by-step Python evaluation.
---
2. Analyze Local Files
from datastore import DataStore
# Parquet — pandas-style analysis
ds = DataStore.from_file("sales.parquet")
top_products = (ds[ds['revenue'] > 0]
.groupby('product')
.agg({'revenue': 'sum', 'quantity': 'sum'})
.sort_values('revenue', ascending=False)
.head(10))
print(top_products)
# CSV with filtering
ds = DataStore.from_file("employees.csv")
senior = ds[(ds['years'] > 5) & (ds['dept'] == 'Engineering')]
print(senior[['name', 'title', 'salary']].sort_values('salary', ascending=False))
# Glob pattern — query all matching files at once
ds = DataStore.from_file("logs/2024-*.csv")
errors = ds[ds['level'] == 'ERROR'].groupby('module')['message'].count()
print(errors.sort_values(ascending=False))
# See the SQL behind any query
print(top_products.to_sql())---
3. Cross-Source Join: MySQL + Parquet
from datastore import DataStore
customers = DataStore.from_mysql(
host="db:3306", database="crm", table="customers",
user="reader", password="pass")
orders = DataStore.from_file("orders.parquet")
result = (customers
.join(orders, left_on="id", right_on="customer_id", how="inner")
.groupby("country")
.agg({"amount": ["sum", "mean"], "order_id": "count"})
.sort_values("sum", ascending=False))
print(result)
# Expected: country-level order summary with total, average, and count
print(result.to_sql())
# Shows the cross-source SQL generated by chdb---
4. Cross-Source Join: S3 + PostgreSQL
from datastore import DataStore
events = DataStore.from_s3(
"s3://analytics/events/2024-*.parquet",
access_key_id="AKIA...", secret_access_key="secret...")
profiles = DataStore.from_postgresql(
host="pg.example.com:5432", database="users",
table="profiles", user="analyst", password="pass")
result = (events
.join(profiles, left_on="user_id", right_on="id")
.filter(events['event_type'] == 'purchase')
.groupby(["country", "age_group"])
.agg({"amount": "sum", "event_id": "count"})
.sort_values("sum", ascending=False))
print(result)
# Expected: purchase events aggregated by country and age group---
5. Three-Way Join: File + Database + Cloud
from datastore import DataStore
products = DataStore.from_file("products.csv")
orders = DataStore.from_mysql(
host="db:3306", database="shop", table="orders",
user="root", password="pass")
reviews = DataStore.from_s3("s3://feedback/reviews.parquet", nosign=True)
result = (orders
.join(products, left_on="product_id", right_on="id")
.join(reviews, left_on="product_id", right_on="product_id")
.groupby("category")
.agg({"amount": "sum", "rating": "mean", "review_id": "count"})
.sort_values("sum", ascending=False))
print(result)
# Expected: category-level summary combining order amounts, review ratings, and counts---
6. Data Lake Formats: Iceberg, Delta, Hudi
from datastore import DataStore
# Apache Iceberg on S3
ds = DataStore.from_iceberg(
"s3://warehouse/iceberg/events",
access_key_id="KEY", secret_access_key="SECRET")
print(ds.head(10))
# Delta Lake
ds = DataStore.from_delta(
"s3://warehouse/delta/transactions",
access_key_id="KEY", secret_access_key="SECRET")
summary = (ds.groupby("category")
.agg({"amount": "sum"})
.sort_values("sum", ascending=False))
print(summary)
# Hudi
ds = DataStore.from_hudi(
"s3://warehouse/hudi/logs",
access_key_id="KEY", secret_access_key="SECRET")
errors = ds[ds['level'] == 'ERROR']
print(errors.head(20))---
7. URI Shorthand Access
from datastore import DataStore
# One-liner for any source
ds = DataStore.uri("sales.parquet")
ds = DataStore.uri("s3://public-data/dataset.parquet?nosign=true")
ds = DataStore.uri("mysql://root:pass@localhost:3306/shop/orders")
ds = DataStore.uri("postgresql://analyst:pass@pg:5432/analytics/events")
ds = DataStore.uri("clickhouse://ch:9440/analytics/hits?user=reader&password=pass")
ds = DataStore.uri("mongodb://user:pass@mongo:27017/logs.app_events")
ds = DataStore.uri("sqlite:///data/local.db?table=users")
ds = DataStore.uri("deltalake:///data/delta/events")
# After creating from any source, same pandas API
result = (ds[ds['value'] > 100]
.groupby('category')
.sum()
.sort_values('value', ascending=False))
print(result)---
8. Cloud Storage Variants
from datastore import DataStore
# AWS S3 (private)
ds = DataStore.from_s3("s3://my-bucket/data.parquet",
access_key_id="AKIA...", secret_access_key="secret...")
# AWS S3 (public)
ds = DataStore.from_s3("s3://public-data/dataset.parquet", nosign=True)
# Google Cloud Storage
ds = DataStore.from_gcs("gs://my-bucket/data.parquet",
hmac_key="KEY", hmac_secret="SECRET")
ds = DataStore.from_gcs("gs://public-bucket/data.parquet", nosign=True)
# Azure Blob Storage
ds = DataStore.from_azure(
connection_string="DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...",
container="data", path="analytics/events.parquet")
# HDFS
ds = DataStore.from_hdfs("hdfs://namenode:9000/warehouse/events/*.parquet")---
9. Cross-Source Write
from datastore import DataStore
# Read from MySQL, transform, write to Parquet
source = DataStore.from_mysql(
host="db:3306", database="shop", table="orders",
user="root", password="pass")
target = DataStore("file", path="output/orders_summary.parquet", format="Parquet")
target.insert_into("category", "total_revenue", "order_count").select_from(
source
.groupby("category")
.select("category", "sum(amount) AS total_revenue", "count() AS order_count")
.filter(source['amount'] > 0)
).execute()
# Read from S3, filter, write to local file
source = DataStore.from_s3("s3://logs/events.parquet", nosign=True)
target = DataStore("file", path="filtered_events.parquet", format="Parquet")
target.insert_into("user_id", "event_type", "ts").select_from(
source.select("user_id", "event_type", "ts")
.filter(source['event_type'] == 'error')
).execute()---
10. Explore Remote Schema
from datastore import DataStore
# Connect to MySQL and browse the schema
mysql_ds = DataStore.from_mysql(
host="db:3306", database="ecommerce",
user="analyst", password="pass")
print(mysql_ds.databases()) # list all databases
print(mysql_ds.tables("ecommerce")) # list tables in a database
# Quick preview of a specific table
orders = DataStore.from_mysql(
host="db:3306", database="ecommerce",
table="orders", user="analyst", password="pass")
print(orders.columns) # → ['id', 'customer_id', 'amount', ...]
print(orders.dtypes) # → {'id': 'UInt64', 'amount': 'Float64', ...}
print(orders.describe()) # → statistics for numeric columns
print(orders.head(5)) # → first 5 rows---
11. Common Errors & Fixes
File not found
from datastore import DataStore
# Error: file not found
ds = DataStore.from_file("nonexistent.parquet")
# → Exception: FILE_NOT_FOUND
# Fix: check the path
import os
print(os.path.exists("nonexistent.parquet")) # → False
ds = DataStore.from_file("data/sales.parquet") # use correct pathDatabase host without port
# Error: connection timeout / refused
ds = DataStore.from_mysql(host="db", database="shop", table="orders",
user="root", password="pass")
# → Connection refused
# Fix: include port in host string
ds = DataStore.from_mysql(host="db:3306", database="shop", table="orders",
user="root", password="pass")Join key type mismatch
# Error: join returns empty or wrong results
users = DataStore({"id": [1, 2, 3], "name": ["Alice", "Bob", "Carol"]}) # id is Int
orders = DataStore({"user_id": ["1", "2", "3"], "amount": [100, 200, 300]}) # user_id is String
result = users.join(orders, left_on="id", right_on="user_id")
print(result) # → empty or incorrect
# Fix: ensure matching types — use .to_sql() to diagnose
print(result.to_sql()) # reveals the type mismatch in the JOIN condition
# Cast in source data, or use assign() to convert types before joiningDebugging with .to_sql()
from datastore import DataStore
ds = DataStore.from_file("sales.parquet")
result = (ds[ds['revenue'] > 1000]
.groupby('product')
.agg({'revenue': 'sum'})
.sort_values('revenue', ascending=False)
.head(10))
# See exactly what SQL will execute
print(result.to_sql())
# Output:
# SELECT "product", sum("revenue") AS "revenue"
# FROM file('sales.parquet', Parquet)
# WHERE "revenue" > 1000
# GROUP BY "product"
# ORDER BY "revenue" DESC
# LIMIT 10{
"version": "4.1.0",
"organization": "ClickHouse Inc",
"date": "March 2026",
"abstract": "Pandas-compatible DataStore API for chdb. Drop-in pandas replacement backed by ClickHouse: same API, 10-100x faster. Supports 16+ data sources (MySQL, PostgreSQL, S3, ClickHouse, MongoDB, Iceberg, Delta Lake, etc.) and 10+ file formats with cross-source joins.",
"references": [
"https://clickhouse.com/docs/chdb",
"https://github.com/chdb-io/chdb"
]
}
chdb DataStore
Agent skill for using chdb's pandas-compatible DataStore API — a drop-in pandas replacement backed by ClickHouse.
Installation
npx skills add clickhouse/agent-skillsWhat's Included
| File | Purpose |
|---|---|
SKILL.md | Skill definition and quick-start guide |
references/api-reference.md | Full DataStore method signatures |
references/connectors.md | All 16+ data source connection methods |
examples/examples.md | 11 runnable examples with expected output |
scripts/verify_install.py | Environment verification script |
Trigger Phrases
This skill activates when you:
- "Analyze this file with pandas"
- "Speed up my pandas code"
- "Query this MySQL/PostgreSQL/S3 table as a DataFrame"
- "Join data from different sources"
- "Use DataStore to..."
- "Import datastore as pd"
Related
- chdb-sql — For raw ClickHouse SQL queries, use the
chdb-sqlskill instead - clickhouse-best-practices — For ClickHouse schema/query optimization
Documentation
DataStore API Reference
Complete method signatures for the DataStore class.
DataStore provides a pandas-compatible API backed by ClickHouse.
Table of Contents
- Import & Construction
- Selection & Filtering
- Sorting & Limiting
- GroupBy & Aggregation
- Joins
- Mutation
- String Accessor (.str)
- DateTime Accessor (.dt)
- Inspection & Execution Triggers
- Writing Data
- Configuration
---
Import & Construction
from datastore import DataStore
# or: from chdb.datastore import DataStore
# or: import chdb.datastore as pd (drop-in replacement)Constructor
DataStore(source=None, table=None, database=":memory:", connection=None, **kwargs)| Source type | Usage |
|---|---|
| dict | DataStore({'col1': [1, 2], 'col2': ['a', 'b']}) |
| pd.DataFrame | DataStore(df) |
| str (source type) | DataStore("file", path="data.parquet") |
| str (source type) | DataStore("mysql", host="host:3306", database="db", table="t", user="u", password="p") |
Factory Methods
See connectors.md for all factory methods (from_file, from_mysql, from_s3, uri, etc.).
---
Selection & Filtering
| Expression | Returns | Description |
|---|---|---|
ds['col'] | LazySeries | Single column |
ds[['c1', 'c2']] | DataStore | Multiple columns |
ds[condition] | DataStore | Boolean filter (e.g., ds[ds['age'] > 25]) |
.select(*fields) | DataStore | SQL-style SELECT with expressions |
.filter(condition) | DataStore | SQL-style WHERE clause |
.where(condition) | DataStore | Mask values where condition is False (pandas semantics) |
result = ds[ds["age"] > 25]
result = ds[(ds["status"] == "active") & (ds["revenue"] > 1000)]
result = ds[["name", "city", "revenue"]]
result = ds.select("name", "revenue * 1.1 AS adjusted_revenue")
result = ds.filter(ds["country"] == "US")
result = ds.where(ds["age"] > 25) # keeps all rows; non-matching values become NaN---
Sorting & Limiting
| Method | Description |
|---|---|
.sort_values(by, ascending=True) | Pandas-style sort (by can be str or list) |
.sort(*columns, ascending=True) | SQL-style ORDER BY |
.orderby(*columns, ascending=True) | Alias for .sort() |
.limit(n) | LIMIT n rows |
.offset(n) | Skip first n rows |
.head(n=5) | First n rows |
.tail(n=5) | Last n rows |
result = ds.sort_values("revenue", ascending=False)
result = ds.sort_values(["country", "city"])
result = ds.head(10)
result = ds.limit(100).offset(50)---
GroupBy & Aggregation
grouped = ds.groupby(*columns) # returns LazyGroupBy
grouped = ds.groupby("dept")
grouped = ds.groupby(["region", "product"])| Method | Description |
|---|---|
.agg(func=None, **kwargs) | Aggregate with named functions |
.sum(), .mean(), .count(), .min(), .max() | Single aggregation |
.std(), .var() | Standard deviation / variance |
.having(condition) | HAVING clause (after aggregation) |
result = ds.groupby("dept")["salary"].mean()
result = ds.groupby("dept").agg({"salary": "mean", "bonus": "sum"})
result = ds.groupby(["region", "product"]).agg(
total_revenue=("revenue", "sum"),
avg_quantity=("quantity", "mean"))---
Joins
.join(other, on=None, how='inner', left_on=None, right_on=None, suffixes=('_x', '_y'))
.merge(other, on=None, how='inner')how | Description |
|---|---|
'inner' | Only matching rows (default) |
'left' | All left rows + matching right |
'right' | All right rows + matching left |
'outer' | All rows from both sides |
'cross' | Cartesian product |
result = orders.join(customers, left_on="customer_id", right_on="id")
result = orders.join(customers, on="customer_id", how="left")
result = ds1.merge(ds2, on="key", how="outer")Cross-source joins work transparently — join a MySQL table with a Parquet file:
mysql_ds = DataStore.from_mysql(host="db:3306", database="crm", table="users", user="root", password="pass")
parquet_ds = DataStore.from_file("orders.parquet")
result = mysql_ds.join(parquet_ds, left_on="id", right_on="user_id")---
Mutation
| Method | Description |
|---|---|
.assign(**kwargs) | Add computed columns |
.with_column(name, expr) | Add single column |
.drop(columns) | Remove columns (str or list) |
.rename(columns={}) | Rename columns via mapping |
.fillna(value) | Fill NaN/NULL values |
.dropna(subset=None) | Drop rows with NaN/NULL |
.distinct(subset=None, keep='first') | Deduplicate rows |
result = ds.assign(
profit=ds["revenue"] - ds["cost"],
margin=lambda x: x["profit"] / x["revenue"])
result = ds.drop("temp_column")
result = ds.rename(columns={"old_name": "new_name"})
result = ds.fillna(0)
result = ds.dropna(subset=["email", "phone"])
result = ds.distinct(subset=["user_id"], keep="first")---
String Accessor (.str)
Access via ds['column'].str.*. 56 methods available, including:
| Method | Description |
|---|---|
.str.upper(), .str.lower() | Case conversion |
.str.strip(), .str.lstrip(), .str.rstrip() | Whitespace trimming |
.str.contains(pattern) | Substring/regex match → boolean |
.str.startswith(prefix), .str.endswith(suffix) | Prefix/suffix check |
.str.replace(old, new) | String replacement |
.str.split(sep) | Split into parts |
.str.len() | String length |
.str.slice(start, stop) | Substring extraction |
.str.cat(sep=None) | Concatenation |
.str.extract(pattern) | Regex group extraction |
.str.pad(width), .str.zfill(width) | Padding |
.str.match(pattern) | Full regex match |
ds["name"].str.upper()
ds["email"].str.contains("@gmail")
ds["code"].str.slice(0, 3)---
DateTime Accessor (.dt)
Access via ds['column'].dt.*. 42+ methods available, including:
| Property/Method | Description |
|---|---|
.dt.year, .dt.month, .dt.day | Date components |
.dt.hour, .dt.minute, .dt.second | Time components |
.dt.dayofweek, .dt.dayofyear | Day ordinals |
.dt.quarter | Quarter (1-4) |
.dt.date, .dt.time | Date/time part |
.dt.strftime(format) | Format as string |
.dt.floor(freq), .dt.ceil(freq) | Round to frequency |
.dt.tz_localize(tz), .dt.tz_convert(tz) | Timezone handling |
.dt.normalize() | Reset time to midnight |
ds["order_date"].dt.year
ds["order_date"].dt.month
ds["timestamp"].dt.hour
ds["created_at"].dt.strftime("%Y-%m-%d")---
Inspection & Execution Triggers
These properties/methods trigger execution of the lazy query:
| Property/Method | Returns | Description |
|---|---|---|
.columns | list | Column names |
.shape | (rows, cols) | Dimensions |
.dtypes | dict | Column types |
.head(n=5) | DataStore | First n rows |
.tail(n=5) | DataStore | Last n rows |
.describe() | DataStore | Summary statistics |
.info() | None | Print DataFrame info |
print(ds) | — | Display results |
len(ds) | int | Row count |
for row in ds | — | Iterate rows |
.equals(other) | bool | Compare DataStores |
These methods do not trigger execution:
| Method | Returns | Description |
|---|---|---|
.to_sql() | str | View the generated SQL |
.explain() | str | Execution plan |
print(ds.columns) # → ['name', 'age', 'city']
print(ds.shape) # → (1000, 3)
print(ds.to_sql()) # → SELECT ... FROM ... WHERE ...
print(ds.describe()) # → statistics table---
Writing Data
Use the insert_into / select_from pattern:
source = DataStore.from_mysql(host="db:3306", database="shop", table="orders", user="root", password="pass")
target = DataStore("file", path="output.parquet", format="Parquet")
target.insert_into("col1", "col2").select_from(
source.select("col1", "col2").filter(source['value'] > 100)
).execute()---
Configuration
from datastore import config
config.use_chdb() # force chDB/SQL backend
config.use_pandas() # force pandas backend
config.prefer_chdb() # prefer chDB when possible, fallback to pandas
config.prefer_pandas() # prefer pandas when possible, fallback to chDB
config.enable_debug() # verbose logging (shows generated SQL)
config.enable_profiling() # performance profilingDataStore Connectors — All Data Sources
Quick reference for connecting DataStore to any data source.
After connecting, all sources share the same pandas API.
Table of Contents
---
Local Files
DataStore.from_file(path, format=None, structure=None, compression=None, **kwargs)Format is auto-detected by extension: .parquet, .csv, .tsv, .json, .jsonl, .arrow, .orc, .avro, .xml.
from datastore import DataStore
ds = DataStore.from_file("sales.parquet")
ds = DataStore.from_file("data.csv")
ds = DataStore.from_file("events.jsonl")
ds = DataStore.from_file("logs/*.csv") # glob pattern
ds = DataStore.from_file("data/2024-*/events.parquet") # nested glob
ds = DataStore.from_file("data.csv.gz") # compressed, auto-detected
ds = DataStore.from_file("data.tsv", format="TabSeparatedWithNames") # explicit formatNotes:
- Glob patterns (
*,**) work for querying multiple files at once - Compression (
.gz,.zst,.bz2,.xz,.lz4) is auto-detected from extension - Use
structureparameter to specify column types:structure="id UInt64, name String"
---
Cloud Storage
S3
DataStore.from_s3(url, access_key_id=None, secret_access_key=None, format=None, nosign=False, **kwargs)# Public bucket (no auth)
ds = DataStore.from_s3("s3://public-data/dataset.parquet", nosign=True)
# Private bucket
ds = DataStore.from_s3("s3://my-bucket/data.parquet",
access_key_id="AKIA...", secret_access_key="secret...")
# Glob pattern
ds = DataStore.from_s3("s3://bucket/logs/2024-*.parquet", nosign=True)GCS (Google Cloud Storage)
DataStore.from_gcs(url, hmac_key=None, hmac_secret=None, format=None, nosign=False, **kwargs)ds = DataStore.from_gcs("gs://my-bucket/data.parquet", nosign=True)
ds = DataStore.from_gcs("gs://private/data.parquet", hmac_key="KEY", hmac_secret="SECRET")Azure Blob Storage
DataStore.from_azure(connection_string, container, path="", format=None, **kwargs)ds = DataStore.from_azure(
connection_string="DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...",
container="data", path="analytics/events.parquet")HDFS
DataStore.from_hdfs(uri, format=None, structure=None, **kwargs)ds = DataStore.from_hdfs("hdfs://namenode:9000/warehouse/events/*.parquet")HTTP/HTTPS URL
DataStore.from_url(url, format=None, structure=None, headers=None, **kwargs)ds = DataStore.from_url("https://example.com/data.csv")---
Databases
MySQL
DataStore.from_mysql(host, database=None, table=None, user=None, password="", port=None, **kwargs)ds = DataStore.from_mysql(
host="db.example.com:3306", database="shop",
table="orders", user="root", password="pass")Note: Port must be included in host string (e.g., "db:3306") or passed via port parameter.
PostgreSQL
DataStore.from_postgresql(host, database=None, table=None, user=None, password="", port=None, **kwargs)ds = DataStore.from_postgresql(
host="pg:5432", database="analytics",
table="events", user="user", password="pass")ClickHouse (Remote)
DataStore.from_clickhouse(host, database=None, table=None, user="default", password="", secure=False, port=None, **kwargs)ds = DataStore.from_clickhouse(host="ch:9000", database="logs", table="access_log")
ds = DataStore.from_clickhouse(host="ch:9440", database="logs", table="hits",
user="reader", password="pass", secure=True)MongoDB
DataStore.from_mongodb(host, database, collection, user, password="", **kwargs)ds = DataStore.from_mongodb(
host="mongo:27017", database="app",
collection="users", user="user", password="pass")SQLite
DataStore.from_sqlite(database_path, table, **kwargs)ds = DataStore.from_sqlite("/data/local.db", "users")Redis
DataStore.from_redis(host, key, structure, password=None, db_index=0, **kwargs)ds = DataStore.from_redis("localhost:6379", key="mydata",
structure="id UInt64, name String, value Float64")---
Data Lakes
Apache Iceberg
DataStore.from_iceberg(url, access_key_id=None, secret_access_key=None, **kwargs)ds = DataStore.from_iceberg("s3://warehouse/iceberg/events",
access_key_id="KEY", secret_access_key="SECRET")Delta Lake
DataStore.from_delta(url, access_key_id=None, secret_access_key=None, **kwargs)ds = DataStore.from_delta("s3://warehouse/delta/transactions",
access_key_id="KEY", secret_access_key="SECRET")Apache Hudi
DataStore.from_hudi(url, access_key_id=None, secret_access_key=None, **kwargs)ds = DataStore.from_hudi("s3://warehouse/hudi/logs",
access_key_id="KEY", secret_access_key="SECRET")---
URI Shorthand
DataStore.uri(uri_string, **kwargs)Universal one-liner that auto-detects source type from the URI scheme:
| Scheme | Example |
|---|---|
| _(path)_ | sales.parquet, /data/file.csv |
file | file:///data/file.csv |
s3, s3a, s3n | s3://bucket/key?nosign=true |
gs, gcs | gs://bucket/path |
az, azure, wasb | az://container/blob?account_name=X&account_key=Y |
hdfs | hdfs://namenode:9000/path |
http, https | https://example.com/data.json |
mysql | mysql://user:pass@host:port/db/table |
postgresql, postgres | postgresql://user:pass@host:port/db/table |
clickhouse | clickhouse://host:port/db/table?user=X&password=Y |
mongodb, mongo | mongodb://user:pass@host:port/db.collection |
sqlite | sqlite:///path/to/db.db?table=name |
redis | redis://host:port/db?key=mykey&password=pass |
iceberg | iceberg://catalog/namespace/table |
deltalake, delta | deltalake:///path/to/table |
hudi | hudi:///path/to/table |
from datastore import DataStore
ds = DataStore.uri("s3://public-data/dataset.parquet?nosign=true")
ds = DataStore.uri("mysql://root:pass@localhost:3306/shop/orders")
ds = DataStore.uri("postgresql://analyst:pass@pg:5432/analytics/events")
ds = DataStore.uri("clickhouse://ch:9440/analytics/hits?user=reader&password=pass")
ds = DataStore.uri("mongodb://user:pass@mongo:27017/logs.app_events")
ds = DataStore.uri("sqlite:///data/local.db?table=users")
ds = DataStore.uri("deltalake:///data/delta/events")---
In-Memory Data
From dict
ds = DataStore({"name": ["Alice", "Bob"], "age": [25, 30]})From pandas DataFrame
ds = DataStore(df)
ds = DataStore.from_df(df, name="my_data")Generated sequences
ds = DataStore.from_numbers(100) # 0..99
ds = DataStore.from_numbers(10, start=5, step=2) # 5, 7, 9, ...Random data (for testing)
ds = DataStore.from_random(
structure="id UInt64, name String, value Float64",
random_seed=42, max_string_length=10)#!/usr/bin/env python3
"""Verify chdb DataStore installation and basic functionality."""
import sys
PASS = "OK"
FAIL = "FAIL"
results = []
def check(name, fn):
try:
fn()
results.append((name, PASS, ""))
print(f" [{PASS}] {name}")
except Exception as e:
results.append((name, FAIL, str(e)))
print(f" [{FAIL}] {name}: {e}")
def check_python_version():
assert sys.version_info >= (3, 9), f"Python 3.9+ required, got {sys.version}"
def check_chdb_import():
import chdb
assert hasattr(chdb, "__version__"), "chdb imported but missing __version__"
print(f" chdb version: {chdb.__version__}")
def check_datastore_import_from_datastore():
from datastore import DataStore
assert DataStore is not None
def check_datastore_import_from_chdb():
from chdb.datastore import DataStore
assert DataStore is not None
def check_datastore_as_pd():
import chdb.datastore as pd
assert hasattr(pd, "DataStore")
def check_basic_operations():
from datastore import DataStore
ds = DataStore({"name": ["Alice", "Bob", "Carol"], "age": [25, 30, 35]})
filtered = ds[ds["age"] > 25]
assert len(filtered) == 2, f"Expected 2 rows, got {len(filtered)}"
def check_sort():
from datastore import DataStore
ds = DataStore({"name": ["Charlie", "Alice", "Bob"], "value": [3, 1, 2]})
sorted_ds = ds.sort_values("value")
cols = sorted_ds.columns
assert "name" in cols and "value" in cols, f"Missing expected columns: {cols}"
assert list(sorted_ds["value"]) == [1, 2, 3], f"Expected sorted values [1, 2, 3], got {list(sorted_ds['value'])}"
def check_groupby():
from datastore import DataStore
ds = DataStore({
"dept": ["Eng", "Sales", "Eng", "Sales"],
"salary": [100, 80, 120, 90],
})
result = ds.groupby("dept")["salary"].mean()
assert len(result) == 2, f"Expected 2 groups, got {len(result)}"
if __name__ == "__main__":
print("chdb DataStore Installation Verification")
print("=" * 45)
check("Python version >= 3.9", check_python_version)
check("import chdb", check_chdb_import)
check("from datastore import DataStore", check_datastore_import_from_datastore)
check("from chdb.datastore import DataStore", check_datastore_import_from_chdb)
check("import chdb.datastore as pd", check_datastore_as_pd)
check("Basic filter operation", check_basic_operations)
check("Sort operation", check_sort)
check("GroupBy aggregation", check_groupby)
print()
print("=" * 45)
passed = sum(1 for _, s, _ in results if s == PASS)
total = len(results)
print(f"Results: {passed}/{total} passed")
if passed < total:
print("\nFailed checks:")
for name, status, err in results:
if status == FAIL:
print(f" - {name}: {err}")
sys.exit(1)
else:
print("All checks passed!")
Related skills
How it compares
Pick chdb-datastore over chdb-sql when you want pandas-style DataFrame code; pick chdb-sql for raw SQL query authoring.
FAQ
What does chdb-datastore do?
Apply chdb-datastore agent skill workflows from documented SKILL.md guidance.
When should I use chdb-datastore?
During build integrations work for backend & apis.
Is chdb-datastore safe to install?
Review the Security Audits panel on this listing before production use.