Announcement: All noncommercial projects registered to use Earth Engine before
April 15, 2025 must
verify noncommercial eligibility to maintain Earth Engine access.
Inner Joins
Stay organized with collections
Save and categorize content based on your preferences.
To enumerate all matches between the elements of two collections, use an
ee.Join.inner()
. The output of an inner join is a
FeatureCollection
(even if joining one ImageCollection
to another ImageCollection
). Each feature in the output represents a
match, where the matching elements are stored in two properties of the feature. For
example, feature.get('primary')
is the element in the primary collection
that matches the element from the secondary collection stored in
feature.get('secondary')
. (Different names for these properties can be
specified as arguments to inner()
, but ‘primary’
and
‘secondary’
are the defaults). One-to-many relationships are represented
by multiple features in the output. If an element in either collection doesn’t have a
match, it is not present in the output.
Join examples using ImageCollection
inputs apply without modification to
FeatureCollection
inputs. It is also possible to join a
FeatureCollection
to an ImageCollection
and vice versa. Consider
the following toy example of inner join:
Code Editor (JavaScript)
// Create the primary collection.
var primaryFeatures = ee.FeatureCollection([
ee.Feature(null, {foo: 0, label: 'a'}),
ee.Feature(null, {foo: 1, label: 'b'}),
ee.Feature(null, {foo: 1, label: 'c'}),
ee.Feature(null, {foo: 2, label: 'd'}),
]);
// Create the secondary collection.
var secondaryFeatures = ee.FeatureCollection([
ee.Feature(null, {bar: 1, label: 'e'}),
ee.Feature(null, {bar: 1, label: 'f'}),
ee.Feature(null, {bar: 2, label: 'g'}),
ee.Feature(null, {bar: 3, label: 'h'}),
]);
// Use an equals filter to specify how the collections match.
var toyFilter = ee.Filter.equals({
leftField: 'foo',
rightField: 'bar'
});
// Define the join.
var innerJoin = ee.Join.inner('primary', 'secondary');
// Apply the join.
var toyJoin = innerJoin.apply(primaryFeatures, secondaryFeatures, toyFilter);
// Print the result.
print('Inner join toy example:', toyJoin);
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)
# Create the primary collection.
primary_features = ee.FeatureCollection([
ee.Feature(None, {'foo': 0, 'label': 'a'}),
ee.Feature(None, {'foo': 1, 'label': 'b'}),
ee.Feature(None, {'foo': 1, 'label': 'c'}),
ee.Feature(None, {'foo': 2, 'label': 'd'}),
])
# Create the secondary collection.
secondary_features = ee.FeatureCollection([
ee.Feature(None, {'bar': 1, 'label': 'e'}),
ee.Feature(None, {'bar': 1, 'label': 'f'}),
ee.Feature(None, {'bar': 2, 'label': 'g'}),
ee.Feature(None, {'bar': 3, 'label': 'h'}),
])
# Use an equals filter to specify how the collections match.
toy_filter = ee.Filter.equals(leftField='foo', rightField='bar')
# Define the join.
inner_join = ee.Join.inner('primary', 'secondary')
# Apply the join.
toy_join = inner_join.apply(primary_features, secondary_features, toy_filter)
# Print the result.
display('Inner join toy example:', toy_join)
In the previous example, notice that the relationship between the tables is defined in the
filter, which indicates that fields ‘foo’
and ‘bar’
are the
join fields. An inner join is then specified and applied to the collections. Inspect
the output and observe that each possible match is represented as one
Feature
.
For a motivated example, consider joining MODIS ImageCollection
objects. MODIS
quality data are sometimes stored in a separate collection from the image data, so an
inner join is convenient for joining the two collections in order to apply the quality
data. In this case, the image acquisition times are identical, so an equals filter
handles the job of specifying this relationship between the two collections:
Code Editor (JavaScript)
// Make a date filter to get images in this date range.
var dateFilter = ee.Filter.date('2014-01-01', '2014-02-01');
// Load a MODIS collection with EVI data.
var mcd43a4 = ee.ImageCollection('MODIS/MCD43A4_006_EVI')
.filter(dateFilter);
// Load a MODIS collection with quality data.
var mcd43a2 = ee.ImageCollection('MODIS/006/MCD43A2')
.filter(dateFilter);
// Define an inner join.
var innerJoin = ee.Join.inner();
// Specify an equals filter for image timestamps.
var filterTimeEq = ee.Filter.equals({
leftField: 'system:time_start',
rightField: 'system:time_start'
});
// Apply the join.
var innerJoinedMODIS = innerJoin.apply(mcd43a4, mcd43a2, filterTimeEq);
// Display the join result: a FeatureCollection.
print('Inner join output:', innerJoinedMODIS);
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)
# Make a date filter to get images in this date range.
date_filter = ee.Filter.date('2014-01-01', '2014-02-01')
# Load a MODIS collection with EVI data.
mcd43a4 = ee.ImageCollection('MODIS/MCD43A4_006_EVI').filter(date_filter)
# Load a MODIS collection with quality data.
mcd43a2 = ee.ImageCollection('MODIS/006/MCD43A2').filter(date_filter)
# Define an inner join.
inner_join = ee.Join.inner()
# Specify an equals filter for image timestamps.
filter_time_eq = ee.Filter.equals(
leftField='system:time_start', rightField='system:time_start'
)
# Apply the join.
inner_joined_modis = inner_join.apply(mcd43a4, mcd43a2, filter_time_eq)
# Display the join result: a FeatureCollection.
display('Inner join output:', inner_joined_modis)
To make use of the joined images in the output FeatureCollection
,
map()
a combining function over the output. For example, the matching
images can be stacked together such that the quality bands are added to the image data:
Code Editor (JavaScript)
// Map a function to merge the results in the output FeatureCollection.
var joinedMODIS = innerJoinedMODIS.map(function(feature) {
return ee.Image.cat(feature.get('primary'), feature.get('secondary'));
});
// Print the result of merging.
print('Inner join, merged bands:', joinedMODIS);
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)
# Map a function to merge the results in the output FeatureCollection.
joined_modis = inner_joined_modis.map(
lambda feature: ee.Image.cat(
feature.get('primary'), feature.get('secondary')
)
)
# Print the result of merging.
display("Inner join, merged 'bands':", joined_modis)
Although this function is mapped over a FeatureCollection
, the result is an
ImageCollection
. Each image in the resultant ImageCollection
has all the bands of the images in the primary collection (in this example just
‘EVI’
) and all the bands of the matching image in the secondary collection
(the quality bands).
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2024-12-27 UTC.
[null,null,["Last updated 2024-12-27 UTC."],[[["\u003cp\u003e\u003ccode\u003eee.Join.inner()\u003c/code\u003e is used to find all matches between elements in two collections, producing a \u003ccode\u003eFeatureCollection\u003c/code\u003e as output.\u003c/p\u003e\n"],["\u003cp\u003eEach feature in the output \u003ccode\u003eFeatureCollection\u003c/code\u003e represents a match, with 'primary' and 'secondary' properties holding the matching elements.\u003c/p\u003e\n"],["\u003cp\u003eFilters define the relationship between collections for the join, such as matching image timestamps or specific feature properties.\u003c/p\u003e\n"],["\u003cp\u003eThe output \u003ccode\u003eFeatureCollection\u003c/code\u003e can be processed further, for instance by combining matched images into a single image with \u003ccode\u003emap()\u003c/code\u003e.\u003c/p\u003e\n"],["\u003cp\u003eInner joins can be applied to \u003ccode\u003eImageCollection\u003c/code\u003e and \u003ccode\u003eFeatureCollection\u003c/code\u003e inputs, enabling operations like merging MODIS image and quality data.\u003c/p\u003e\n"]]],["To enumerate matches between two collections, use `ee.Join.inner()`, which outputs a `FeatureCollection`. Each feature represents a match, storing elements from the primary and secondary collections in properties named 'primary' and 'secondary'. Use `ee.Filter.equals()` to define how collections match. The `innerJoin.apply()` joins collections. Matching elements that are not present in the filter will not appear in the output. Joined features can be merged into an `ImageCollection` by mapping a function that combines matched images.\n"],null,["# Inner Joins\n\nTo enumerate all matches between the elements of two collections, use an\n`ee.Join.inner()`. The output of an inner join is a\n`FeatureCollection` (even if joining one `ImageCollection`\nto another `ImageCollection`). Each feature in the output represents a\nmatch, where the matching elements are stored in two properties of the feature. For\nexample, `feature.get('primary')` is the element in the primary collection\nthat matches the element from the secondary collection stored in\n`feature.get('secondary')`. (Different names for these properties can be\nspecified as arguments to `inner()`, but `'primary'` and\n`'secondary'` are the defaults). One-to-many relationships are represented\nby multiple features in the output. If an element in either collection doesn't have a\nmatch, it is not present in the output.\n\nJoin examples using `ImageCollection` inputs apply without modification to\n`FeatureCollection` inputs. It is also possible to join a\n`FeatureCollection` to an `ImageCollection` and vice versa. Consider\nthe following toy example of inner join:\n\n### Code Editor (JavaScript)\n\n```javascript\n// Create the primary collection.\nvar primaryFeatures = ee.FeatureCollection([\n ee.Feature(null, {foo: 0, label: 'a'}),\n ee.Feature(null, {foo: 1, label: 'b'}),\n ee.Feature(null, {foo: 1, label: 'c'}),\n ee.Feature(null, {foo: 2, label: 'd'}),\n]);\n\n// Create the secondary collection.\nvar secondaryFeatures = ee.FeatureCollection([\n ee.Feature(null, {bar: 1, label: 'e'}),\n ee.Feature(null, {bar: 1, label: 'f'}),\n ee.Feature(null, {bar: 2, label: 'g'}),\n ee.Feature(null, {bar: 3, label: 'h'}),\n]);\n\n// Use an equals filter to specify how the collections match.\nvar toyFilter = ee.Filter.equals({\n leftField: 'foo',\n rightField: 'bar'\n});\n\n// Define the join.\nvar innerJoin = ee.Join.inner('primary', 'secondary');\n\n// Apply the join.\nvar toyJoin = innerJoin.apply(primaryFeatures, secondaryFeatures, toyFilter);\n\n// Print the result.\nprint('Inner join toy example:', toyJoin);\n```\nPython setup\n\nSee the [Python Environment](/earth-engine/guides/python_install) page for information on the Python API and using\n`geemap` for interactive development. \n\n```python\nimport ee\nimport geemap.core as geemap\n```\n\n### Colab (Python)\n\n```python\n# Create the primary collection.\nprimary_features = ee.FeatureCollection([\n ee.Feature(None, {'foo': 0, 'label': 'a'}),\n ee.Feature(None, {'foo': 1, 'label': 'b'}),\n ee.Feature(None, {'foo': 1, 'label': 'c'}),\n ee.Feature(None, {'foo': 2, 'label': 'd'}),\n])\n\n# Create the secondary collection.\nsecondary_features = ee.FeatureCollection([\n ee.Feature(None, {'bar': 1, 'label': 'e'}),\n ee.Feature(None, {'bar': 1, 'label': 'f'}),\n ee.Feature(None, {'bar': 2, 'label': 'g'}),\n ee.Feature(None, {'bar': 3, 'label': 'h'}),\n])\n\n# Use an equals filter to specify how the collections match.\ntoy_filter = ee.Filter.equals(leftField='foo', rightField='bar')\n\n# Define the join.\ninner_join = ee.Join.inner('primary', 'secondary')\n\n# Apply the join.\ntoy_join = inner_join.apply(primary_features, secondary_features, toy_filter)\n\n# Print the result.\ndisplay('Inner join toy example:', toy_join)\n```\n\nIn the previous example, notice that the relationship between the tables is defined in the\nfilter, which indicates that fields `'foo'` and `'bar'` are the\njoin fields. An inner join is then specified and applied to the collections. Inspect\nthe output and observe that each possible match is represented as one\n`Feature`.\n\nFor a motivated example, consider joining MODIS `ImageCollection` objects. MODIS\nquality data are sometimes stored in a separate collection from the image data, so an\ninner join is convenient for joining the two collections in order to apply the quality\ndata. In this case, the image acquisition times are identical, so an equals filter\nhandles the job of specifying this relationship between the two collections:\n\n### Code Editor (JavaScript)\n\n```javascript\n// Make a date filter to get images in this date range.\nvar dateFilter = ee.Filter.date('2014-01-01', '2014-02-01');\n\n// Load a MODIS collection with EVI data.\nvar mcd43a4 = ee.ImageCollection('MODIS/MCD43A4_006_EVI')\n .filter(dateFilter);\n\n// Load a MODIS collection with quality data.\nvar mcd43a2 = ee.ImageCollection('MODIS/006/MCD43A2')\n .filter(dateFilter);\n\n// Define an inner join.\nvar innerJoin = ee.Join.inner();\n\n// Specify an equals filter for image timestamps.\nvar filterTimeEq = ee.Filter.equals({\n leftField: 'system:time_start',\n rightField: 'system:time_start'\n});\n\n// Apply the join.\nvar innerJoinedMODIS = innerJoin.apply(mcd43a4, mcd43a2, filterTimeEq);\n\n// Display the join result: a FeatureCollection.\nprint('Inner join output:', innerJoinedMODIS);\n```\nPython setup\n\nSee the [Python Environment](/earth-engine/guides/python_install) page for information on the Python API and using\n`geemap` for interactive development. \n\n```python\nimport ee\nimport geemap.core as geemap\n```\n\n### Colab (Python)\n\n```python\n# Make a date filter to get images in this date range.\ndate_filter = ee.Filter.date('2014-01-01', '2014-02-01')\n\n# Load a MODIS collection with EVI data.\nmcd43a4 = ee.ImageCollection('MODIS/MCD43A4_006_EVI').filter(date_filter)\n\n# Load a MODIS collection with quality data.\nmcd43a2 = ee.ImageCollection('MODIS/006/MCD43A2').filter(date_filter)\n\n# Define an inner join.\ninner_join = ee.Join.inner()\n\n# Specify an equals filter for image timestamps.\nfilter_time_eq = ee.Filter.equals(\n leftField='system:time_start', rightField='system:time_start'\n)\n\n# Apply the join.\ninner_joined_modis = inner_join.apply(mcd43a4, mcd43a2, filter_time_eq)\n\n# Display the join result: a FeatureCollection.\ndisplay('Inner join output:', inner_joined_modis)\n```\n\nTo make use of the joined images in the output `FeatureCollection`,\n`map()` a combining function over the output. For example, the matching\nimages can be stacked together such that the quality bands are added to the image data:\n\n### Code Editor (JavaScript)\n\n```javascript\n// Map a function to merge the results in the output FeatureCollection.\nvar joinedMODIS = innerJoinedMODIS.map(function(feature) {\n return ee.Image.cat(feature.get('primary'), feature.get('secondary'));\n});\n\n// Print the result of merging.\nprint('Inner join, merged bands:', joinedMODIS);\n```\nPython setup\n\nSee the [Python Environment](/earth-engine/guides/python_install) page for information on the Python API and using\n`geemap` for interactive development. \n\n```python\nimport ee\nimport geemap.core as geemap\n```\n\n### Colab (Python)\n\n```python\n# Map a function to merge the results in the output FeatureCollection.\njoined_modis = inner_joined_modis.map(\n lambda feature: ee.Image.cat(\n feature.get('primary'), feature.get('secondary')\n )\n)\n\n# Print the result of merging.\ndisplay(\"Inner join, merged 'bands':\", joined_modis)\n```\n\nAlthough this function is mapped over a `FeatureCollection`, the result is an\n`ImageCollection`. Each image in the resultant `ImageCollection`\nhas all the bands of the images in the primary collection (in this example just\n`'EVI'`) and all the bands of the matching image in the secondary collection\n(the quality bands)."]]