Querying with JSON
Beacon also supports a structured JSON query format. This is useful when you want to build queries programmatically (without generating SQL), because the query is expressed as a typed object: select columns, apply filters, sort, and choose an output format.
JSON queries are sent to the same endpoint as SQL:
POST /api/query
TIP
If you are querying from Python (notebooks/pipelines), using the Beacon Python SDK is recommended: Beacon Python SDK docs
Request shape
At the top level, the request is a Query object:
- Either
{ "sql": "..." }(SQL mode) - Or a JSON query body (JSON mode)
In both cases you can optionally include output.
Minimal JSON query
{
"select": ["time", "latitude", "longitude", "temp"],
"limit": 10
}Notes:
selectis required.- If
fromis omitted, Beacon uses the configured default table. - If
outputis omitted, Beacon streams Arrow IPC (application/vnd.apache.arrow.stream).
Selecting columns
select accepts multiple forms:
- Column name string:
"temp" - Column with alias:
{ "column": "sea_surface_temperature", "alias": "sst" }- Function call:
{ "function": "round", "args": ["temp"], "alias": "temp_rounded" }Choosing the data source (from)
You can query either a registered table or a set of files as an ad-hoc source.
Query a table
Use GET /api/tables to discover the table names available on your server.
{
"from": "some_table",
"select": ["time", "temp"],
"limit": 10
}Query files directly
from also supports a format+paths shape (example with NetCDF):
{
"from": { "netcdf": { "paths": ["my-file.nc"] } },
"select": ["time", "temp"],
"limit": 100
}Other supported from formats include zarr, parquet, csv, arrow, and odv.
Filters
Use the filter field to constrain results.
Range filter (between)
{
"select": ["time", "temp"],
"filter": { "column": "temp", "min": 2, "max": 10 }
}Equality filter
{
"select": ["time", "platform"],
"filter": { "column": "platform", "eq": "SHIP" }
}Combine filters (and/or)
{
"select": ["time", "latitude", "longitude", "temp"],
"filter": {
"and": [
{ "column": "temp", "min": 2, "max": 10 },
{ "column": "latitude", "min": -10, "max": 10 }
]
},
"limit": 10000
}GeoJSON spatial filter
This filter checks whether a point (lon/lat columns) falls within a provided GeoJSON geometry.
{
"select": ["time", "longitude", "latitude", "temp"],
"filter": {
"longitude_column": "longitude",
"latitude_column": "latitude",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[4.0, 52.0],
[6.0, 52.0],
[6.0, 54.0],
[4.0, 54.0],
[4.0, 52.0]
]
]
}
},
"limit": 10000
}Sorting, limits, offsets
sort_by:[{"asc": "time"}]or[{"desc": "temp"}]limit: maximum rows returnedoffset: skip N rows
Example:
{
"select": ["time", "temp"],
"sort_by": [{ "desc": "time" }],
"limit": 100
}Distinct
Use distinct to return distinct combinations.
{
"distinct": {
"on": ["platform"],
"select": ["platform"]
},
"select": ["platform"]
}Output formats
To download a single file, set output.format.
Simple formats:
{
"select": ["time", "temp"],
"output": { "format": "csv" }
}Formats with options:
{
"select": ["longitude", "latitude", "time", "temp"],
"output": {
"format": { "geoparquet": { "longitude_column": "longitude", "latitude_column": "latitude" } }
}
}{
"select": ["time", "depth", "temp"],
"output": { "format": { "nd_netcdf": { "dimension_columns": ["time", "depth"] } } }
}Tips
- Discover columns with
GET /api/default-table-schema. - Validate query bodies with
POST /api/parse-query. - Use the
x-beacon-query-idheader to fetch metrics fromGET /api/query/metrics/{query_id}.