Skip to main content
Leaf Lake exposes your agronomic data through four tables. This page documents the schema of each table and provides example queries you can adapt. Leaf Lake uses BigQuery SQL. All queries are automatically scoped to your API owner account — you only see data belonging to your Leaf users.

The points table

Each row represents a single data point from a machine file. The columns match the standardGeojson point properties produced by Leaf’s machine data pipeline. See Sample Output for the full property definitions.

Common columns (all operation types)

ColumnTypeDescription
operationTypestringplanted, harvested, applied, or tillage
geometrystringGeographic location as WKT (convert with ST_GeogFromText)
timestamptimestampWhen the data was recorded
cropstringNormalized crop name
fieldIdsarrayLeaf field UUID(s) associated with this point
leafUserIdstringThe Leaf user who owns this data
areafloatArea covered at this point
distancefloatDistance traveled
headingfloatMachine heading in degrees
speedfloatMachine speed
elevationfloatElevation
equipmentWidthfloatWidth of the implement
recordingStatusstringRecording status (e.g. On)
sectionIdintSection/row identifier
machinerylistMachine and implement names
varietystringCrop variety name

Planted columns

ColumnTypeDescription
seedRateintSeeds per area at this point
seedRateTargetintTarget seed rate
seedDepthfloatPlanting depth
downForcefloatDown force reading
singulationfloatMeter singulation percentage
skipsfloatSkip percentage
doublesfloatDouble percentage

Harvested columns

ColumnTypeDescription
harvestMoisturefloatGrain moisture percentage
wetMassfloatWet mass
wetMassPerAreafloatWet mass per area
wetVolumefloatWet volume
wetVolumePerAreafloatWet volume per area
dryMassfloatDry mass
dryMassPerAreafloatDry mass per area
dryVolumefloatDry volume
dryVolumePerAreafloatDry volume per area

Applied columns

ColumnTypeDescription
appliedRatefloatApplication rate at this point
appliedRateTargetfloatTarget application rate
productslistArray of product objects with name and rate
tankMixNamestringName of the tank mix

Tillage columns

ColumnTypeDescription
tillageDepthTargetfloatTarget tillage depth
tillageDepthActualfloatActual tillage depth
tillTypelistTillage implement type

Filtering by field

Filter points to a specific Leaf field using the fieldIds column. No WKT boundary polygon needed.
SELECT *
FROM points
WHERE operationType = 'harvested'
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
You can also filter spatially using a WKT polygon with ST_Intersects, or join against the fields or states_counties tables. See the examples below.

Operations query examples

List operations on a field

See what operation types, crops, and date ranges exist for a field.
SELECT
    EXTRACT(YEAR FROM timestamp) AS op_year,
    operationType,
    crop,
    COUNT(*) AS point_count,
    MIN(timestamp) AS start_time,
    MAX(timestamp) AS end_time
FROM points
WHERE 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
GROUP BY EXTRACT(YEAR FROM timestamp), operationType, crop
ORDER BY op_year, start_time

Planted: seed rate by variety and year

SELECT
    crop,
    EXTRACT(YEAR FROM timestamp) AS op_year,
    variety,
    COUNT(*) AS point_count,
    ROUND(MIN(seedRate), 0) AS min_seed_rate,
    ROUND(AVG(seedRate), 0) AS avg_seed_rate,
    ROUND(MAX(seedRate), 0) AS max_seed_rate
FROM points
WHERE operationType = 'planted'
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
GROUP BY crop, variety, EXTRACT(YEAR FROM timestamp)
ORDER BY op_year

Planted: spatial point data

Retrieve individual planting points with coordinates for mapping.
SELECT
    crop,
    EXTRACT(YEAR FROM timestamp) AS planting_year,
    seedRate,
    ST_X(ST_GeogFromText(geometry)) AS lon,
    ST_Y(ST_GeogFromText(geometry)) AS lat
FROM points
WHERE operationType = 'planted'
  AND seedRate IS NOT NULL
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)

Applied: summary by product and year

SELECT
    EXTRACT(YEAR FROM timestamp) AS op_year,
    tankMixName,
    COUNT(*) AS point_count,
    MIN(timestamp) AS start_time,
    MAX(timestamp) AS end_time
FROM points
WHERE operationType = 'applied'
  AND timestamp >= '2025-01-01'
  AND timestamp <= '2025-12-31'
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
GROUP BY EXTRACT(YEAR FROM timestamp), tankMixName
ORDER BY op_year, start_time

Applied: point data with product details

SELECT
    TO_JSON_STRING(products) AS products_json,
    appliedRate,
    timestamp,
    ST_X(ST_GeogFromText(geometry)) AS lon,
    ST_Y(ST_GeogFromText(geometry)) AS lat
FROM points
WHERE operationType = 'applied'
  AND timestamp >= '2025-01-01'
  AND timestamp <= '2025-12-31'
  AND appliedRate IS NOT NULL
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)

Harvested: yield statistics

Leaf Lake stores yield in metric units. Convert to bu/ac using crop-specific factors (corn: 62.77 kg/ha per bu/ac, soybeans: 67.25 kg/ha per bu/ac).
SELECT
    crop,
    EXTRACT(YEAR FROM timestamp) AS op_year,
    COUNT(*) AS point_count,
    ROUND(AVG(wetMassPerArea) / 62.77, 1) AS avg_yield_bu_ac,
    ROUND(MIN(wetMassPerArea) / 62.77, 1) AS min_yield_bu_ac,
    ROUND(MAX(wetMassPerArea) / 62.77, 1) AS max_yield_bu_ac,
    ROUND(STDDEV(wetMassPerArea) / 62.77, 1) AS std_yield_bu_ac
FROM points
WHERE operationType = 'harvested'
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
GROUP BY crop, EXTRACT(YEAR FROM timestamp)
ORDER BY op_year DESC

Harvested: outlier filtering with CTEs

Filter yield data to remove statistical outliers. Adjust the standard deviation threshold to control how aggressively outliers are removed. This replaces pipeline-level reprocessing — change the threshold and re-run the query.
WITH stats AS (
    SELECT
        crop,
        EXTRACT(YEAR FROM timestamp) AS harvest_year,
        AVG(wetMassPerArea) AS mean_yield,
        STDDEV(wetMassPerArea) AS std_yield
    FROM points
    WHERE operationType = 'harvested'
      AND wetMassPerArea IS NOT NULL
      AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
    GROUP BY crop, EXTRACT(YEAR FROM timestamp)
)
SELECT
    p.crop,
    EXTRACT(YEAR FROM p.timestamp) AS harvest_year,
    p.wetMassPerArea / 62.77 AS yield_bu_ac,
    p.harvestMoisture AS moisture,
    ST_X(ST_GeogFromText(p.geometry)) AS lon,
    ST_Y(ST_GeogFromText(p.geometry)) AS lat
FROM points p
JOIN stats s ON p.crop = s.crop
  AND EXTRACT(YEAR FROM p.timestamp) = s.harvest_year
WHERE p.operationType = 'harvested'
  AND p.wetMassPerArea IS NOT NULL
  AND 'YOUR_FIELD_UUID' IN UNNEST(p.fieldIds)
  AND p.wetMassPerArea BETWEEN s.mean_yield - 3 * s.std_yield
                            AND s.mean_yield + 3 * s.std_yield

Tillage: basic query

SELECT
    EXTRACT(YEAR FROM timestamp) AS op_year,
    tillType,
    COUNT(*) AS point_count,
    ROUND(AVG(tillageDepthTarget), 1) AS avg_depth_target,
    MIN(timestamp) AS start_time,
    MAX(timestamp) AS end_time
FROM points
WHERE operationType = 'tillage'
  AND 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
GROUP BY EXTRACT(YEAR FROM timestamp), tillType
ORDER BY op_year

The fields table

Leaf field boundaries synced from the Fields API. Automatically scoped to your API owner account.
ColumnTypeDescription
idstring (UUID)The Leaf field ID
field_geometrygeographyUnion of all boundary geometries for the field
boundary_id_listarrayList of boundary IDs
updated_datedateLast update date

Join operations with field boundaries

Use the fields table to spatially join points with field boundaries instead of hardcoding WKT polygons.
SELECT
    f.id AS field_id,
    p.operationType,
    p.crop,
    COUNT(*) AS point_count
FROM points p
JOIN fields f ON ST_Intersects(ST_GeogFromText(p.geometry), f.field_geometry)
WHERE f.id = 'YOUR_FIELD_UUID'
GROUP BY f.id, p.operationType, p.crop

The ssurgo table

The SSURGO (Soil Survey Geographic Database) table contains USDA soil map unit polygons with associated attributes.
ColumnTypeDescription
mukeystringMap unit key — unique identifier for the soil map unit
soil_namestringSoil map unit name
countystringCounty name
drainage_classstringSoil drainage classification (e.g. “Well drained”, “Poorly drained”)
farmland_classstringFarmland classification (e.g. “Prime farmland”)
hydric_ratingstringHydric soil rating
flooding_frequencystringFlooding frequency class
ponding_frequencystringPonding frequency class
aws0_150floatAvailable water storage, 0-150 cm depth
aws0_999floatAvailable water storage, full soil profile
geometrystringBoundary of the soil map unit (convert with ST_GeogFromText)

Query soil units intersecting a field

Derive the field extent from your points using a CTE, then intersect with SSURGO.
WITH field_envelope AS (
    SELECT ST_ConvexHull(ST_Union_Agg(ST_GeogFromText(geometry))) AS field_geom
    FROM points
    WHERE 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
)
SELECT
    mukey,
    soil_name,
    county,
    drainage_class,
    farmland_class,
    ROUND(ST_Area(ST_Intersection(
        ST_GeogFromText(ssurgo.geometry),
        fe.field_geom
    )) / 4046.86, 2) AS acres,
    ST_AsText(ST_Intersection(
        ST_GeogFromText(ssurgo.geometry),
        fe.field_geom
    )) AS clipped_geometry
FROM ssurgo
CROSS JOIN field_envelope fe
WHERE ST_Intersects(ST_GeogFromText(ssurgo.geometry), fe.field_geom)
ORDER BY mukey ASC

Join harvest data with soil types

Calculate average yield by soil map unit within a field. This is a spatial join between the points table and ssurgo.
WITH field_envelope AS (
    SELECT ST_ConvexHull(ST_Union_Agg(ST_GeogFromText(geometry))) AS field_geom
    FROM points
    WHERE 'YOUR_FIELD_UUID' IN UNNEST(fieldIds)
),
field_soils AS (
    SELECT
        mukey,
        soil_name,
        drainage_class,
        farmland_class,
        ssurgo.geometry AS soil_geom
    FROM ssurgo
    CROSS JOIN field_envelope fe
    WHERE ST_Intersects(ST_GeogFromText(ssurgo.geometry), fe.field_geom)
),
yield_by_soil AS (
    SELECT
        s.mukey,
        AVG(p.wetMassPerArea) AS avg_yield,
        COUNT(*) AS harvest_points
    FROM points p
    JOIN field_soils s ON ST_Intersects(ST_GeogFromText(s.soil_geom), ST_GeogFromText(p.geometry))
    WHERE p.operationType = 'harvested'
      AND p.timestamp >= '2025-01-01'
      AND p.timestamp <= '2025-12-31'
      AND 'YOUR_FIELD_UUID' IN UNNEST(p.fieldIds)
    GROUP BY s.mukey
)
SELECT
    s.mukey,
    s.soil_name,
    s.drainage_class,
    s.farmland_class,
    ROUND(COALESCE(y.avg_yield, 0) / 62.77, 1) AS avg_yield_bu_ac,
    y.harvest_points
FROM field_soils s
LEFT JOIN yield_by_soil y ON s.mukey = y.mukey
ORDER BY avg_yield_bu_ac DESC

The states_counties table

US state and county boundary polygons for geographic grouping and filtering.
ColumnTypeDescription
STATEstringState code (e.g. IL, IA)
COUNTYNAMEstringCounty name
geometrygeographyState or county boundary

Filter operations by county

SELECT
    c.STATE,
    c.COUNTYNAME,
    EXTRACT(YEAR FROM p.timestamp) AS op_year,
    p.operationType,
    p.crop,
    COUNT(*) AS point_count
FROM points p
JOIN states_counties c ON ST_Intersects(ST_GeogFromText(p.geometry), c.geometry)
WHERE c.STATE = 'IL'
  AND c.COUNTYNAME = 'La Salle'
GROUP BY c.STATE, c.COUNTYNAME, EXTRACT(YEAR FROM p.timestamp), p.operationType, p.crop
ORDER BY op_year

What to do next

Last modified on March 24, 2026