The MetaJdbc driver enables reading Meta data (Facebook Graph API, Instagram Business, and Meta Ads) via JDBC with SQL.
The following conventions apply:
jdbc:meta:jdbc:meta:https://graph.facebook.com/v25.0)public is used by defaultfbk_page_insights_daily, meta_ad_account)/me/accountsmeta_ad_stats, meta_conversion_stats)jdbc:meta:https://graph.facebook.com/v25.0
The part after jdbc:meta: is the Graph API base URL including API version. It takes precedence over api.baseUrl in the spec.
Properties props = new Properties();
props.setProperty("token", "EAAx...");
props.setProperty("spec", "/opt/datasqill/config/meta-spec.json");
Connection conn = DriverManager.getConnection(
"jdbc:meta:https://graph.facebook.com/v25.0", props);
Date range and object selection belong in SQL (FILTER), not in the connection — see FILTER.
| Property | Description | Required |
|---|---|---|
token |
System user access token (Facebook Login for Business) | Yes |
spec |
Path to spec file (.json, .yaml, .yml, .ini; filesystem or classpath:...) |
No (default: bundled spec) |
von_dt |
Start date (yyyy-MM-dd) |
Via FILTER in SQL (fallback: connection property) |
bis_dt |
End date (yyyy-MM-dd) |
Via FILTER in SQL (fallback: connection property) |
load_type |
delta (default) or full for async ad insights |
Via FILTER or connection property |
stdoutlog |
Debug output: meta, http, rows, cursor, or all (combine with +) |
No |
Property names are case-insensitive. config is an alias for spec.
Spec path:
/opt/datasqill/config/meta-spec.json
/opt/datasqill/config/meta-spec.yaml
classpath:de/softquadrat/jdbc/meta/meta-spec.json
Only static connection data (token, spec) belongs in the keyfile. The load date range goes in SQL:
jdbc:meta:https://graph.facebook.com/v25.0:dboptionlist={token=EAAx...,spec=/opt/datasqill/meta-spec.json}:
A single system user token is used. The driver:
GET /me/accounts and obtains page access tokensact_* ad account callsRequired permissions (excerpt):
pages_read_engagement, pages_show_listinstagram_basic, instagram_manage_insightsads_read (for paid media)Open one JDBC connection per ETL job and run one SELECT per target table.
SELECT page_id, name, insta_user_id FROM fbk_page_insights;
SELECT page_id, dat, page_total_media_view_unique
FROM fbk_page_insights_daily
FILTER von_dt='2025-01-01' AND bis_dt='2025-01-31'
;
SELECT ad_account_id, name FROM meta_ad_account;
SELECT ad_account_id, ad_id, impressions, datum
FROM meta_ad_stats
FILTER von_dt='2025-01-01' AND bis_dt='2025-01-31' AND load_type=delta
;
The driver iterates internally over all pages or ad accounts. Use FILTER to narrow the date range or select individual pages. There is no WHERE and no LIMIT.
Note: datasqill SQL does not support line comments with --. meta-staging.sql contains executable statements only.
| Data | Behavior |
|---|---|
Page list (/me/accounts) |
once per connection, then cached |
| Ad account list | once per connection, then cached |
| Insights data | fetched from API on every SELECT |
Multiple SELECTs in the same connection avoid a second /me/accounts call. Running the same SELECT twice performs the full API run again.
| Table | Content | von_dt/bis_dt |
|---|---|---|
fbk_page_insights |
Facebook pages + linked IG accounts | No |
fbk_page_insights_daily |
Facebook page insights per day | Yes |
ins_page_insights |
Instagram follower snapshot | No |
ins_page_insights_daily |
Instagram account insights per day | Yes |
ins_media |
Instagram media objects (posts/reels) | Optional (filter by publish date) |
ins_media_insights |
Instagram media insights (lifetime) | Yes (filter by publish date) |
| Table | Content | von_dt/bis_dt |
|---|---|---|
meta_ad_account |
Ad accounts | No |
meta_campaign |
Campaigns (all accounts) | No |
meta_adset |
Ad sets | No |
meta_ad |
Ads | No |
meta_ad_stats |
Ad performance (async) | Yes (with load_type=delta) |
meta_conversion_stats |
Conversion stats (async) | Yes (with load_type=delta) |
Full SQL example: meta-staging.sql
The spec defines API endpoints, requested fields/metrics, limits, and filters. Formats: JSON (recommended), YAML, or INI (legacy).
Full reference spec: meta-spec.json
Short YAML example: meta-spec-example.yaml
{
"api": {
"version": "v25.0",
"baseUrl": "https://graph.facebook.com"
},
"fbk_page_insights_daily": {
"endpoint": "insights",
"fields": [
"page_total_media_view_unique",
"page_media_view",
"page_post_engagements"
],
"tablename": "stage.fbk_page_insights_daily"
}
}
api:
version: v25.0
baseUrl: https://graph.facebook.com
fbk_page_insights_daily:
endpoint: insights
fields:
- page_total_media_view_unique
- page_post_engagements
Each root-level key (except api) is the name of a predefined SQL table and parameterizes its API calls (fields, endpoint, limit, …). New table names cannot be added via spec alone.
| Field | Description | |
|---|---|---|
endpoint |
Graph API endpoint relative to page/ad account ID | |
endpoints |
Comma-separated endpoints (only ad_account, e.g. owned + client accounts) |
|
fields |
Fields or insights metrics to request (array or CSV string) | |
limit |
Page size for paginated requests | |
filtering |
Meta API filtering expression (paid media) | |
breakdowns |
Breakdowns for async insights | |
tablename |
Staging target name (documentation) | JDBC ignores |
For fbk_page_insights_daily, ins_page_insights_daily, and ins_media_insights, metric columns are read from fields in the spec. New metrics can be added in the spec without recompiling the driver.
Master data columns (page_id, media_id, ad_account_id, …) remain fixed in the driver.
The Graph API uses different load patterns per data type (page iteration, async jobs, media pagination, pivot logic), implemented in the driver as fixed fetch strategies.
| Configuration | Spec | Driver (Java) |
|---|---|---|
| SQL table name | No | Yes — 12 fixed names |
| Fetch strategy (how data is loaded) | No | Yes — e.g. page insights daily, async ad stats |
Master data columns (page_id, ad_account_id, …) |
No | Yes |
Metric columns (fields) |
Yes | Base columns + spec |
| API endpoints, limits, filters, breakdowns | Yes | — |
tablename (staging target) |
Yes | JDBC ignores |
Practical implications:
Each spec section (e.g. fbk_page_insights_daily) maps to exactly one predefined SQL table. The section name must match the table name.
SELECT page_id, name, insta_user_id
FROM fbk_page_insights
;
SELECT page_id, dat, page_total_media_view_unique, page_post_engagements
FROM fbk_page_insights_daily
FILTER von_dt='2025-01-01' AND bis_dt='2025-01-31'
;
SELECT page_id, dat, page_total_media_view_unique
FROM fbk_page_insights_daily
FILTER von_dt='2025-01-01' AND bis_dt='2025-01-31' AND page_id='330419580652874'
;
In datasqill SQL the clause is FILTER (not WHERE). It controls driver API parameters — mainly the load date range and optionally individual pages.
Syntax: param=value, multiple parameters joined with AND. Values in single quotes or unquoted.
| FILTER parameter | Alias | Effect |
|---|---|---|
von_dt |
from_date |
Start of date range (yyyy-MM-dd) |
bis_dt |
to_date |
End of date range (yyyy-MM-dd) |
page_id |
— | Load only this Facebook page |
insta_user_id |
— | Load only this Instagram account |
load_type |
— | delta or full for async ad insights |
Priority: FILTER values override connection properties. In datasqill ETL jobs, set the date range in SQL — only administrators maintain connection/keyfile (token, spec).
Examples:
SELECT ad_id, impressions, date_start
FROM meta_ad_stats
FILTER von_dt='2025-01-01' AND bis_dt='2025-01-31' AND load_type=delta
;
SELECT insta_user_id, dat, reach
FROM ins_page_insights_daily
FILTER from_date='2025-01-01' AND to_date='2025-01-31' AND insta_user_id='17841400000'
;
INSERT, UPDATE, DELETEWHERE, ORDER BY-- …)COLUMNS clauseColumn selection via SELECT works — only referenced columns are returned.
Column names that are SQL keywords must be double-quoted:
SELECT insta_user_id, media_id, "timestamp", permalink FROM ins_media;
Applies to timestamp in ins_media and ins_media_insights.
follower_count (daily)The follower_count metric in ins_page_insights_daily can only be queried for the last 30 days (excluding today). For older days in the FILTER range, the driver still loads other metrics (reach, likes, …) and sets follower_count to NULL — without an API error.
The system schema provides virtual tables:
| Table | Content |
|---|---|
table_list |
All registered Meta tables |
column_list |
Columns (including dynamic metrics from spec) |
pk_list |
Primary keys |
SELECT table_name, remarks
FROM system.table_list
WHERE table_name LIKE 'meta_%'
;
SELECT column_name, type_name
FROM system.column_list
WHERE table_name = 'fbk_page_insights_daily'
;
token → GET /me/accounts → all pages
├─ fbk_page_insights → page master data
├─ fbk_page_insights_daily → GET /{page-id}/insights (per page)
├─ ins_page_insights → GET /{ig-user-id}
├─ ins_page_insights_daily → GET /{ig-user-id}/insights (per day)
├─ ins_media → GET /{ig-user-id}/media
└─ ins_media_insights → GET /{media-id}/insights (per media)
token → ad accounts (owned + client)
├─ meta_ad_account → master data
├─ meta_campaign/adset/ad → paginated entity calls per account
└─ meta_ad_stats → POST async insights → poll → GET results
stdoutlog=meta+http+rows
| Level | Output |
|---|---|
meta |
API calls, page/account resolution, skipped metrics |
http |
HTTP method and URL |
rows |
Rows read per batch |
cursor |
Opened table |
Common errors:
| Message | Cause / fix |
|---|---|
(#100) The value must be a valid insights metric |
Metric deprecated in Graph API v25 — remove from spec or driver skips individually |
Missing "von_dt" |
Add FILTER von_dt='…' AND bis_dt='…' (required for daily/delta tables) |
Sorry, I cannot understand -- … |
No -- comments in datasqill SQL — remove the comment line |
mismatched input 'timestamp' |
Quote the column as "timestamp" |
follower_count … last 30 days |
Historical days: driver skips follower_count automatically; use a new build |
HTTP 429 |
Rate limit — driver retries automatically; reduce load |
| Long runtime without output | Normal with many pages/media — enable stdoutlog |
Meta regularly deprecates insights metrics (e.g. page_impressions_unique in v25). The default spec uses current metrics (page_total_media_view_unique, page_media_view). Check the Meta Insights documentation on API errors.
ins_media_insights performs one API call per media object. Loads with many posts can take a long time.
Invalid metrics per media_type (FEED, REELS, STORY) are skipped automatically.