Save-All Joins

  • Saving joins represent one-to-many relationships in Earth Engine by storing matches from a secondary collection as a property in the primary collection.

  • ee.Join.saveAll() stores all matching features from the secondary collection as a list in a new property of the primary collection's features, dropping unmatched primary features.

  • This approach is useful for scenarios like associating all MODIS images within a specific time window to each Landsat image in a collection.

  • The example code demonstrates filtering and joining Landsat and MODIS collections based on their timestamps, storing the matching MODIS images in a 'terra' property on each Landsat image.

Saving joins are one way of representing one-to-many relationships in Earth Engine. Unlike an inner join, a saving join stores matches from the secondary collection as a named property of the features in the primary collection. To save all such matches, use an ee.Join.saveAll(). If there is a one-to-many relationship, a saveAll() join stores all matching features as an ee.List. Unmatched elements in the primary collection are dropped. For example, suppose there is a need to get all MODIS imagery acquired within two days of each Landsat image in a collection. This example uses a saveAll() join for that purpose:

Code Editor (JavaScript)

// Load a primary collection: Landsat imagery.
var primary = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
    .filterDate('2014-04-01', '2014-06-01')
    .filterBounds(ee.Geometry.Point(-122.092, 37.42));

// Load a secondary collection: MODIS imagery.
var modSecondary = ee.ImageCollection('MODIS/006/MOD09GA')
    .filterDate('2014-03-01', '2014-07-01');

// Define an allowable time difference: two days in milliseconds.
var twoDaysMillis = 2 * 24 * 60 * 60 * 1000;

// Create a time filter to define a match as overlapping timestamps.
var timeFilter = ee.Filter.or(
  ee.Filter.maxDifference({
    difference: twoDaysMillis,
    leftField: 'system:time_start',
    rightField: 'system:time_end'
  }),
  ee.Filter.maxDifference({
    difference: twoDaysMillis,
    leftField: 'system:time_end',
    rightField: 'system:time_start'
  })
);

// Define the join.
var saveAllJoin = ee.Join.saveAll({
  matchesKey: 'terra',
  ordering: 'system:time_start',
  ascending: true
});

// Apply the join.
var landsatModis = saveAllJoin.apply(primary, modSecondary, timeFilter);

// Display the result.
print('Join.saveAll:', landsatModis);

Python setup

See the Python Environment page for information on the Python API and using geemap for interactive development.

import ee
import geemap.core as geemap

Colab (Python)

# Load a primary collection: Landsat imagery.
primary = (
    ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
    .filterDate('2014-04-01', '2014-06-01')
    .filterBounds(ee.Geometry.Point(-122.092, 37.42))
)

# Load a secondary collection: MODIS imagery.
mod_secondary = ee.ImageCollection('MODIS/006/MOD09GA').filterDate(
    '2014-03-01', '2014-07-01'
)

# Define an allowable time difference: two days in milliseconds.
two_days_millis = 2 * 24 * 60 * 60 * 1000

# Create a time filter to define a match as overlapping timestamps.
time_filter = ee.Filter.Or(
    ee.Filter.maxDifference(
        difference=two_days_millis,
        leftField='system:time_start',
        rightField='system:time_end',
    ),
    ee.Filter.maxDifference(
        difference=two_days_millis,
        leftField='system:time_end',
        rightField='system:time_start',
    ),
)

# Define the join.
save_all_join = ee.Join.saveAll(
    matchesKey='terra', ordering='system:time_start', ascending=True
)

# Apply the join.
landsat_modis = save_all_join.apply(primary, mod_secondary, time_filter)

# Display the result.
display('Join.saveAll:', landsat_modis)

In this example, note that the secondary MODIS collection is pre-filtered to be chronologically similar to the primary Landsat collection for efficiency. To compare the Landsat acquisition time to the MODIS composite time, which has a daily range, the filter compares the endpoints of the image timestamps. The join is defined with the name of the property used to store the list of matches for each Landsat image (‘terra’) and optional parameter to sort the list of matches by the system:time_start property

Inspection of the result indicates that images within the primary collection have the added terra property which stores a list of the matching MODIS images.